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
|
@@ -9,62 +9,7 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
|
|
|
9
9
|
|
|
10
10
|
const color__default = /*#__PURE__*/_interopDefaultCompat(color);
|
|
11
11
|
|
|
12
|
-
const
|
|
13
|
-
<html lang="en">
|
|
14
|
-
<head>
|
|
15
|
-
<meta charset="UTF-8">
|
|
16
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
17
|
-
<title>$title</title>
|
|
18
|
-
</head>
|
|
19
|
-
<body style="margin: 0; overscroll-behavior: none; user-select: none; touch-action: none;">
|
|
20
|
-
<script type="module" src="$indexPath"><\/script>
|
|
21
|
-
<div style="width: 100dvw; height: 100dvh; overflow: hidden;" id="root"></div>
|
|
22
|
-
</body>
|
|
23
|
-
</html>`;
|
|
24
|
-
const ViteHtmlContent = `<!DOCTYPE html>
|
|
25
|
-
<html lang="en">
|
|
26
|
-
<head>
|
|
27
|
-
<meta charset="UTF-8">
|
|
28
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
29
|
-
<title>$title</title>
|
|
30
|
-
</head>
|
|
31
|
-
<body>
|
|
32
|
-
<div id="app"></div>
|
|
33
|
-
<script type="module" src="$indexPath"><\/script>
|
|
34
|
-
</body>
|
|
35
|
-
</html>`;
|
|
36
|
-
const IndexContent = `import { StrictMode } from 'react'
|
|
37
|
-
import { createRoot } from 'react-dom/client'
|
|
38
|
-
import { App } from './app.js'
|
|
39
|
-
|
|
40
|
-
createRoot(document.getElementById('root')!).render(
|
|
41
|
-
<StrictMode>
|
|
42
|
-
<App />
|
|
43
|
-
</StrictMode>,
|
|
44
|
-
)`;
|
|
45
|
-
const ViteIndexContent = `import './style.css'
|
|
46
|
-
|
|
47
|
-
document.querySelector('#app')!.innerHTML = \`
|
|
48
|
-
<h1>Hello Vite!</h1>
|
|
49
|
-
<p>Edit src/main.ts and save to see HMR in action.</p>
|
|
50
|
-
\``;
|
|
51
|
-
const ViteStyleContent = `body {
|
|
52
|
-
font-family: system-ui, -apple-system, sans-serif;
|
|
53
|
-
margin: 0;
|
|
54
|
-
padding: 2rem;
|
|
55
|
-
min-height: 100vh;
|
|
56
|
-
background: #1a1a1a;
|
|
57
|
-
color: #fff;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
h1 {
|
|
61
|
-
color: #646cff;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
a {
|
|
65
|
-
color: #646cff;
|
|
66
|
-
}`;
|
|
67
|
-
const GitAttributes = [
|
|
12
|
+
const gitAttributesContent = [
|
|
68
13
|
"* text eol=lf",
|
|
69
14
|
"*.png binary",
|
|
70
15
|
"*.jpg binary",
|
|
@@ -89,55 +34,6 @@ const GitAttributes = [
|
|
|
89
34
|
"*.glb binary",
|
|
90
35
|
"*.gltf binary"
|
|
91
36
|
].join("\n");
|
|
92
|
-
const defaultFormatterConfig = {
|
|
93
|
-
printWidth: 102,
|
|
94
|
-
tabWidth: 2,
|
|
95
|
-
useTabs: false,
|
|
96
|
-
semi: true,
|
|
97
|
-
singleQuote: true,
|
|
98
|
-
trailingComma: "es5",
|
|
99
|
-
bracketSpacing: true,
|
|
100
|
-
arrowParens: "always"
|
|
101
|
-
};
|
|
102
|
-
const defaultPrettierConfig = {
|
|
103
|
-
$schema: "https://json.schemastore.org/prettierrc",
|
|
104
|
-
...defaultFormatterConfig,
|
|
105
|
-
overrides: [
|
|
106
|
-
{
|
|
107
|
-
files: ["*.md", "**/*.md"],
|
|
108
|
-
options: { semi: false }
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
files: ["*.yml", "*.yaml", "**/*.yml", "**/*.yaml"],
|
|
112
|
-
options: { semi: false }
|
|
113
|
-
}
|
|
114
|
-
]
|
|
115
|
-
};
|
|
116
|
-
const defaultOxfmtConfig = {
|
|
117
|
-
printWidth: defaultFormatterConfig.printWidth,
|
|
118
|
-
tabWidth: defaultFormatterConfig.tabWidth,
|
|
119
|
-
useTabs: defaultFormatterConfig.useTabs,
|
|
120
|
-
semi: defaultFormatterConfig.semi,
|
|
121
|
-
singleQuote: defaultFormatterConfig.singleQuote,
|
|
122
|
-
trailingComma: defaultFormatterConfig.trailingComma,
|
|
123
|
-
bracketSpacing: defaultFormatterConfig.bracketSpacing,
|
|
124
|
-
arrowParens: defaultFormatterConfig.arrowParens
|
|
125
|
-
};
|
|
126
|
-
const defaultLinterConfig = {
|
|
127
|
-
ignorePatterns: ["dist"],
|
|
128
|
-
rules: {
|
|
129
|
-
noUnusedVars: {
|
|
130
|
-
level: "warn",
|
|
131
|
-
argsIgnorePattern: "^_",
|
|
132
|
-
varsIgnorePattern: "^_",
|
|
133
|
-
caughtErrorsIgnorePattern: "^_"
|
|
134
|
-
},
|
|
135
|
-
noUnusedExpressions: {
|
|
136
|
-
level: "warn",
|
|
137
|
-
allowShortCircuit: true
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
37
|
|
|
142
38
|
const ALL_AI_PLATFORMS = ["agents", "claude"];
|
|
143
39
|
const AI_PLATFORM_LABELS = {
|
|
@@ -148,12 +44,15 @@ const AI_PLATFORM_HINTS = {
|
|
|
148
44
|
agents: "OpenAI, Cursor, Windsurf, etc.",
|
|
149
45
|
claude: "Claude Code"
|
|
150
46
|
};
|
|
151
|
-
function
|
|
152
|
-
const { platforms, isMonorepo, configStrategy, ...rest } = params;
|
|
47
|
+
function renderAiFiles(files, params) {
|
|
48
|
+
const { platforms, isMonorepo, configStrategy, hasTypecheck, ...rest } = params;
|
|
153
49
|
if (platforms.length === 0) return;
|
|
154
50
|
const content = generateWorkspace({
|
|
155
51
|
...rest,
|
|
156
|
-
isMonorepo: !!isMonorepo
|
|
52
|
+
isMonorepo: !!isMonorepo,
|
|
53
|
+
configStrategy: configStrategy ?? "stealth",
|
|
54
|
+
hasTypecheck: hasTypecheck ?? false
|
|
55
|
+
});
|
|
157
56
|
const pointer = "See [`AGENTS.md`](./Agents.md) for agent context.\n";
|
|
158
57
|
const hasAgents = platforms.includes("agents");
|
|
159
58
|
const hasClaude = platforms.includes("claude");
|
|
@@ -168,31 +67,115 @@ function generateAiFiles(files, params) {
|
|
|
168
67
|
}
|
|
169
68
|
}
|
|
170
69
|
function generateWorkspace(ctx) {
|
|
171
|
-
const {
|
|
70
|
+
const { packageManager, linter, formatter, hasTypecheck } = ctx;
|
|
71
|
+
const exampleFiles = "src/App.tsx src/core/systems/move-entity.ts";
|
|
72
|
+
const commands = getAfterEditingCommands(ctx, exampleFiles);
|
|
172
73
|
const sections = [
|
|
173
|
-
|
|
74
|
+
"# Workspace Tools",
|
|
174
75
|
"",
|
|
175
|
-
`- **Type:** ${isMonorepo ? "pnpm monorepo" : "standalone project"}`,
|
|
176
76
|
`- **Package Manager:** ${packageManager}`,
|
|
177
77
|
`- **Linter:** ${linter}`,
|
|
178
78
|
`- **Formatter:** ${formatter}`,
|
|
179
79
|
"",
|
|
180
|
-
"##
|
|
181
|
-
""
|
|
182
|
-
`- \`${packageManager} test\` \u2014 run tests`,
|
|
183
|
-
`- \`${packageManager} build\` \u2014 build`,
|
|
184
|
-
`- \`${packageManager} lint\` and \`${packageManager} format\` \u2014 run before committing`
|
|
80
|
+
"## After Editing",
|
|
81
|
+
""
|
|
185
82
|
];
|
|
186
|
-
if (
|
|
83
|
+
if (hasTypecheck) {
|
|
187
84
|
sections.push(
|
|
188
|
-
""
|
|
189
|
-
|
|
190
|
-
|
|
85
|
+
"\u2705 After editing files, check the types for errors and then format and lint only the files changed for the current task."
|
|
86
|
+
);
|
|
87
|
+
} else {
|
|
88
|
+
sections.push(
|
|
89
|
+
"\u2705 After editing files, format and lint only the files changed for the current task."
|
|
191
90
|
);
|
|
192
91
|
}
|
|
193
|
-
sections.push("");
|
|
92
|
+
sections.push("", "```sh", "# Example");
|
|
93
|
+
if (hasTypecheck) {
|
|
94
|
+
sections.push(runScript(packageManager, "typecheck"));
|
|
95
|
+
}
|
|
96
|
+
sections.push(
|
|
97
|
+
"# Run format and lint for only files modified",
|
|
98
|
+
commands.format,
|
|
99
|
+
commands.lint,
|
|
100
|
+
"```",
|
|
101
|
+
"",
|
|
102
|
+
"\u274C Avoid unless explicitly approved:",
|
|
103
|
+
"",
|
|
104
|
+
"```sh",
|
|
105
|
+
runScript(packageManager, "format"),
|
|
106
|
+
runScript(packageManager, "lint"),
|
|
107
|
+
"```",
|
|
108
|
+
""
|
|
109
|
+
);
|
|
194
110
|
return sections.join("\n");
|
|
195
111
|
}
|
|
112
|
+
function getAfterEditingCommands(ctx, files) {
|
|
113
|
+
return {
|
|
114
|
+
format: getFormatChangedFilesCommand(ctx, files),
|
|
115
|
+
lint: getLintChangedFilesCommand(ctx, files)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function getFormatChangedFilesCommand(ctx, files) {
|
|
119
|
+
const exec = getExecCommand(ctx.packageManager);
|
|
120
|
+
if (ctx.formatter === "prettier") {
|
|
121
|
+
const configPath = getPrettierConfigPath(ctx);
|
|
122
|
+
const ignorePath = getPrettierIgnorePath(ctx);
|
|
123
|
+
const configFlag2 = configPath == null ? "" : ` --config ${configPath}`;
|
|
124
|
+
const ignoreFlag = ignorePath == null ? "" : ` --ignore-path ${ignorePath}`;
|
|
125
|
+
return `${exec} prettier${configFlag2}${ignoreFlag} --write ${files}`;
|
|
126
|
+
}
|
|
127
|
+
if (ctx.formatter === "oxfmt") {
|
|
128
|
+
const configPath = getOxfmtConfigPath(ctx);
|
|
129
|
+
return `${exec} oxfmt -c ${configPath} --write ${files}`;
|
|
130
|
+
}
|
|
131
|
+
const configFlag = ctx.isMonorepo || ctx.configStrategy === "root" ? "" : " --config-path .config";
|
|
132
|
+
return `${exec} biome format${configFlag} --write ${files}`;
|
|
133
|
+
}
|
|
134
|
+
function getLintChangedFilesCommand(ctx, files) {
|
|
135
|
+
const exec = getExecCommand(ctx.packageManager);
|
|
136
|
+
if (ctx.linter === "oxlint") {
|
|
137
|
+
if (!ctx.isMonorepo) {
|
|
138
|
+
return runScript(ctx.packageManager, "lint", files);
|
|
139
|
+
}
|
|
140
|
+
return `${exec} oxlint ${files}`;
|
|
141
|
+
}
|
|
142
|
+
if (ctx.linter === "eslint") {
|
|
143
|
+
const configFlag2 = ctx.configStrategy === "stealth" ? " --config .config/eslint.config.js" : "";
|
|
144
|
+
return `${exec} eslint${configFlag2} ${files}`;
|
|
145
|
+
}
|
|
146
|
+
const configFlag = ctx.isMonorepo || ctx.configStrategy === "root" ? "" : " --config-path .config";
|
|
147
|
+
return `${exec} biome lint${configFlag} ${files}`;
|
|
148
|
+
}
|
|
149
|
+
function getPrettierConfigPath(ctx) {
|
|
150
|
+
if (ctx.isMonorepo) return ".config/prettier/base.json";
|
|
151
|
+
if (ctx.configStrategy === "stealth") return ".config/prettier.json";
|
|
152
|
+
return void 0;
|
|
153
|
+
}
|
|
154
|
+
function getPrettierIgnorePath(ctx) {
|
|
155
|
+
if (ctx.isMonorepo) return ".config/prettier/prettierignore";
|
|
156
|
+
if (ctx.configStrategy === "stealth") return ".config/prettierignore";
|
|
157
|
+
return void 0;
|
|
158
|
+
}
|
|
159
|
+
function getOxfmtConfigPath(ctx) {
|
|
160
|
+
if (ctx.isMonorepo) return ".config/oxfmt/base.json";
|
|
161
|
+
if (ctx.configStrategy === "stealth") return ".config/oxfmt.json";
|
|
162
|
+
return "oxfmt.json";
|
|
163
|
+
}
|
|
164
|
+
function runScript(packageManager, script, args) {
|
|
165
|
+
const suffix = args == null ? "" : ` ${args}`;
|
|
166
|
+
if (packageManager === "npm") {
|
|
167
|
+
return `npm run ${script}${args == null ? "" : ` --${suffix}`}`;
|
|
168
|
+
}
|
|
169
|
+
if (packageManager === "yarn") {
|
|
170
|
+
return `yarn ${script}${suffix}`;
|
|
171
|
+
}
|
|
172
|
+
return `${packageManager} ${script}${args == null ? "" : ` --${suffix}`}`;
|
|
173
|
+
}
|
|
174
|
+
function getExecCommand(packageManager) {
|
|
175
|
+
if (packageManager === "npm") return "npm exec --";
|
|
176
|
+
if (packageManager === "yarn") return "yarn exec";
|
|
177
|
+
return `${packageManager} exec`;
|
|
178
|
+
}
|
|
196
179
|
|
|
197
180
|
function getLanguageFromTemplate(template) {
|
|
198
181
|
return template.endsWith("-js") ? "javascript" : "typescript";
|
|
@@ -201,59 +184,49 @@ function getBaseTemplate(template) {
|
|
|
201
184
|
return template.replace("-js", "");
|
|
202
185
|
}
|
|
203
186
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
} catch {
|
|
210
|
-
return fallback;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
function compareNumericSemver(a, b) {
|
|
214
|
-
const aParts = a.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
215
|
-
const bParts = b.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
216
|
-
const maxLength = Math.max(aParts.length, bParts.length);
|
|
217
|
-
for (let index = 0; index < maxLength; index += 1) {
|
|
218
|
-
const difference = (aParts[index] ?? 0) - (bParts[index] ?? 0);
|
|
219
|
-
if (difference !== 0) {
|
|
220
|
-
return difference;
|
|
187
|
+
function unique(...array) {
|
|
188
|
+
const set = /* @__PURE__ */ new Set();
|
|
189
|
+
for (const arr of array) {
|
|
190
|
+
for (const item of arr) {
|
|
191
|
+
set.add(item);
|
|
221
192
|
}
|
|
222
193
|
}
|
|
223
|
-
return
|
|
194
|
+
return Array.from(set);
|
|
224
195
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
} catch {
|
|
232
|
-
return fallback;
|
|
196
|
+
|
|
197
|
+
function merge(target, modification) {
|
|
198
|
+
const targetLabel = JSON.stringify(target);
|
|
199
|
+
const modificationLabel = JSON.stringify(modification);
|
|
200
|
+
if (modification == null) {
|
|
201
|
+
throw new Error(`Cannot merge "${modificationLabel}" modification into target "${targetLabel}"`);
|
|
233
202
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return getLatestNpmVersion("npm", "11.0.0");
|
|
243
|
-
}
|
|
244
|
-
async function getLatestNodeVersion() {
|
|
245
|
-
try {
|
|
246
|
-
const response = await fetch("https://nodejs.org/dist/index.json");
|
|
247
|
-
const data = await response.json();
|
|
248
|
-
const latestVersion = data[0];
|
|
249
|
-
if (latestVersion) {
|
|
250
|
-
return latestVersion.version.replace(/^v/, "");
|
|
203
|
+
if (target == null) {
|
|
204
|
+
return modification;
|
|
205
|
+
}
|
|
206
|
+
if (Array.isArray(target)) {
|
|
207
|
+
if (!Array.isArray(modification)) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
`Cannot merge non-array modification "${modificationLabel}" into array target "${targetLabel}"`
|
|
210
|
+
);
|
|
251
211
|
}
|
|
252
|
-
return
|
|
253
|
-
}
|
|
254
|
-
|
|
212
|
+
return [...target, ...modification];
|
|
213
|
+
}
|
|
214
|
+
if (typeof target === "object") {
|
|
215
|
+
if (typeof modification !== "object") {
|
|
216
|
+
throw new Error(
|
|
217
|
+
`Cannot merge non-object modification "${modificationLabel}" into object target "${targetLabel}"`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
const result = { ...target };
|
|
221
|
+
for (const modificationKey in modification) {
|
|
222
|
+
result[modificationKey] = merge(target[modificationKey], modification[modificationKey]);
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
255
225
|
}
|
|
226
|
+
console.warn(`target "${targetLabel}" is overwritten with modification "${modificationLabel}"`);
|
|
227
|
+
return modification;
|
|
256
228
|
}
|
|
229
|
+
|
|
257
230
|
function validateNameSegment(segment, label) {
|
|
258
231
|
if (!segment.length) {
|
|
259
232
|
return `${label} is required`;
|
|
@@ -297,27 +270,83 @@ function validatePackageName(name) {
|
|
|
297
270
|
}
|
|
298
271
|
return validateNameSegment(name, "Package name");
|
|
299
272
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
273
|
+
|
|
274
|
+
function generateRandomName() {
|
|
275
|
+
const adjectives = [
|
|
276
|
+
"red",
|
|
277
|
+
"blue",
|
|
278
|
+
"green",
|
|
279
|
+
"yellow",
|
|
280
|
+
"purple",
|
|
281
|
+
"orange",
|
|
282
|
+
"pink",
|
|
283
|
+
"black",
|
|
284
|
+
"white",
|
|
285
|
+
"tiny",
|
|
286
|
+
"big",
|
|
287
|
+
"small",
|
|
288
|
+
"large",
|
|
289
|
+
"huge",
|
|
290
|
+
"giant",
|
|
291
|
+
"mini",
|
|
292
|
+
"mega",
|
|
293
|
+
"super",
|
|
294
|
+
"happy",
|
|
295
|
+
"sad",
|
|
296
|
+
"angry",
|
|
297
|
+
"calm",
|
|
298
|
+
"quiet",
|
|
299
|
+
"loud",
|
|
300
|
+
"silent",
|
|
301
|
+
"noisy",
|
|
302
|
+
"shiny",
|
|
303
|
+
"dull",
|
|
304
|
+
"bright",
|
|
305
|
+
"dark",
|
|
306
|
+
"fuzzy",
|
|
307
|
+
"smooth",
|
|
308
|
+
"rough",
|
|
309
|
+
"soft"
|
|
310
|
+
];
|
|
311
|
+
const nouns = [
|
|
312
|
+
"apple",
|
|
313
|
+
"banana",
|
|
314
|
+
"cherry",
|
|
315
|
+
"date",
|
|
316
|
+
"elderberry",
|
|
317
|
+
"fig",
|
|
318
|
+
"grape",
|
|
319
|
+
"honeydew",
|
|
320
|
+
"cat",
|
|
321
|
+
"dog",
|
|
322
|
+
"elephant",
|
|
323
|
+
"fox",
|
|
324
|
+
"giraffe",
|
|
325
|
+
"horse",
|
|
326
|
+
"iguana",
|
|
327
|
+
"jaguar",
|
|
328
|
+
"mountain",
|
|
329
|
+
"river",
|
|
330
|
+
"ocean",
|
|
331
|
+
"desert",
|
|
332
|
+
"forest",
|
|
333
|
+
"jungle",
|
|
334
|
+
"meadow",
|
|
335
|
+
"valley",
|
|
336
|
+
"star",
|
|
337
|
+
"moon",
|
|
338
|
+
"sun",
|
|
339
|
+
"planet",
|
|
340
|
+
"comet",
|
|
341
|
+
"asteroid",
|
|
342
|
+
"galaxy",
|
|
343
|
+
"universe"
|
|
344
|
+
];
|
|
345
|
+
const randomAdjective = adjectives[Math.floor(Math.random() * adjectives.length)];
|
|
346
|
+
const randomNoun = nouns[Math.floor(Math.random() * nouns.length)];
|
|
347
|
+
return `${randomAdjective}-${randomNoun}`;
|
|
320
348
|
}
|
|
349
|
+
|
|
321
350
|
async function pathExists(path) {
|
|
322
351
|
try {
|
|
323
352
|
await promises.access(path, fs.constants.F_OK);
|
|
@@ -393,81 +422,82 @@ async function detectTooling(root) {
|
|
|
393
422
|
} catch {
|
|
394
423
|
return { linter: void 0, formatter: void 0 };
|
|
395
424
|
}
|
|
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
|
-
"
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async function getLatestNpmVersion(packageName, fallback) {
|
|
428
|
+
try {
|
|
429
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`);
|
|
430
|
+
const data = await response.json();
|
|
431
|
+
return data.version;
|
|
432
|
+
} catch {
|
|
433
|
+
return fallback;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
function compareNumericSemver(a, b) {
|
|
437
|
+
const aParts = a.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
438
|
+
const bParts = b.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
439
|
+
const maxLength = Math.max(aParts.length, bParts.length);
|
|
440
|
+
for (let index = 0; index < maxLength; index += 1) {
|
|
441
|
+
const difference = (aParts[index] ?? 0) - (bParts[index] ?? 0);
|
|
442
|
+
if (difference !== 0) {
|
|
443
|
+
return difference;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return 0;
|
|
447
|
+
}
|
|
448
|
+
async function getLatestNpmMajorVersion(packageName, majorVersion, fallback) {
|
|
449
|
+
try {
|
|
450
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}`);
|
|
451
|
+
const data = await response.json();
|
|
452
|
+
const latestMatchingVersion = Object.keys(data.versions ?? {}).filter((version) => version.split(".")[0] === majorVersion).sort((a, b) => compareNumericSemver(b, a))[0];
|
|
453
|
+
return latestMatchingVersion ?? fallback;
|
|
454
|
+
} catch {
|
|
455
|
+
return fallback;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
async function getLatestPnpmVersion() {
|
|
459
|
+
return getLatestNpmVersion("pnpm", "10.11.0");
|
|
460
|
+
}
|
|
461
|
+
async function getLatestYarnVersion() {
|
|
462
|
+
return getLatestNpmVersion("yarn", "4.6.0");
|
|
463
|
+
}
|
|
464
|
+
async function getLatestNpmCliVersion() {
|
|
465
|
+
return getLatestNpmVersion("npm", "11.0.0");
|
|
466
|
+
}
|
|
467
|
+
async function getLatestNodeVersion() {
|
|
468
|
+
try {
|
|
469
|
+
const response = await fetch("https://nodejs.org/dist/index.json");
|
|
470
|
+
const data = await response.json();
|
|
471
|
+
const latestVersion = data[0];
|
|
472
|
+
if (latestVersion) {
|
|
473
|
+
return latestVersion.version.replace(/^v/, "");
|
|
474
|
+
}
|
|
475
|
+
return "25.0.0";
|
|
476
|
+
} catch {
|
|
477
|
+
return "25.0.0";
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function parseWorkspaceYamlContent(content) {
|
|
482
|
+
const directories = [];
|
|
483
|
+
let inPackagesSection = false;
|
|
484
|
+
for (const line of content.split("\n")) {
|
|
485
|
+
const trimmed = line.trim();
|
|
486
|
+
if (trimmed === "packages:") {
|
|
487
|
+
inPackagesSection = true;
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
if (inPackagesSection && trimmed && !line.startsWith(" ") && !line.startsWith(" ") && !trimmed.startsWith("-")) {
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
if (inPackagesSection && trimmed.startsWith("-")) {
|
|
494
|
+
const entry = trimmed.slice(1).trim().replace(/^["']|["']$/g, "").replace(/^\.\//, "").replace(/\/\*.*$/, "");
|
|
495
|
+
if (entry && !entry.startsWith(".")) {
|
|
496
|
+
directories.push(entry);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return directories;
|
|
471
501
|
}
|
|
472
502
|
|
|
473
503
|
const PACKAGE_VERSION_DEFINITIONS = {
|
|
@@ -495,6 +525,7 @@ const PACKAGE_VERSION_DEFINITIONS = {
|
|
|
495
525
|
leva: { fallbackVersion: "0.10.0" },
|
|
496
526
|
oxfmt: { fallbackVersion: "0.21.0" },
|
|
497
527
|
oxlint: { fallbackVersion: "1.36.0" },
|
|
528
|
+
"oxlint-tsgolint": { fallbackVersion: "0.22.1" },
|
|
498
529
|
prettier: { fallbackVersion: "3.4.2" },
|
|
499
530
|
react: { fallbackVersion: "19.0.0" },
|
|
500
531
|
"react-dom": { fallbackVersion: "19.0.0" },
|
|
@@ -651,6 +682,9 @@ async function resolveMonorepoRootPackageVersions(params) {
|
|
|
651
682
|
const packageNames = /* @__PURE__ */ new Set();
|
|
652
683
|
const explicitVersions = new Set(Object.keys(params.versions ?? {}));
|
|
653
684
|
addPackageName(packageNames, explicitVersions, getLinterPackage(params.linter));
|
|
685
|
+
if (params.linter === "oxlint") {
|
|
686
|
+
addPackageName(packageNames, explicitVersions, "oxlint-tsgolint");
|
|
687
|
+
}
|
|
654
688
|
if (params.formatter !== "biome" || params.linter !== "biome") {
|
|
655
689
|
addPackageName(packageNames, explicitVersions, getFormatterPackage(params.formatter));
|
|
656
690
|
}
|
|
@@ -760,6 +794,9 @@ function collectProjectPackageNames(options) {
|
|
|
760
794
|
} else if (linter === "oxlint") {
|
|
761
795
|
if (!inWorkspace) {
|
|
762
796
|
addPackageName(packageNames, explicitVersions, "oxlint");
|
|
797
|
+
if (isTypescript) {
|
|
798
|
+
addPackageName(packageNames, explicitVersions, "oxlint-tsgolint");
|
|
799
|
+
}
|
|
763
800
|
}
|
|
764
801
|
} else if (linter === "biome") {
|
|
765
802
|
addPackageName(packageNames, explicitVersions, "@biomejs/biome");
|
|
@@ -794,7 +831,7 @@ function isEnabledOption(option) {
|
|
|
794
831
|
return option != null && option !== false;
|
|
795
832
|
}
|
|
796
833
|
|
|
797
|
-
function
|
|
834
|
+
function renderTypescriptConfig(baseTemplateOrParams) {
|
|
798
835
|
const params = typeof baseTemplateOrParams === "string" ? { baseTemplate: baseTemplateOrParams } : baseTemplateOrParams;
|
|
799
836
|
const {
|
|
800
837
|
baseTemplate,
|
|
@@ -841,10 +878,7 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
841
878
|
const tsConfig = {
|
|
842
879
|
$schema: "https://json.schemastore.org/tsconfig",
|
|
843
880
|
files: [],
|
|
844
|
-
references: [
|
|
845
|
-
{ path: "./.config/tsconfig.app.json" },
|
|
846
|
-
{ path: "./.config/tsconfig.node.json" }
|
|
847
|
-
]
|
|
881
|
+
references: [{ path: "./.config/tsconfig.app.json" }, { path: "./.config/tsconfig.node.json" }]
|
|
848
882
|
};
|
|
849
883
|
files["tsconfig.json"] = {
|
|
850
884
|
type: "text",
|
|
@@ -864,6 +898,7 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
864
898
|
composite: true,
|
|
865
899
|
rewriteRelativeImportExtensions: true,
|
|
866
900
|
erasableSyntaxOnly: true,
|
|
901
|
+
noEmit: true,
|
|
867
902
|
...isReact || isR3f ? { jsx: "react-jsx" } : {}
|
|
868
903
|
},
|
|
869
904
|
include: ["../src", "../tests"]
|
|
@@ -885,7 +920,8 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
885
920
|
skipLibCheck: true,
|
|
886
921
|
composite: true,
|
|
887
922
|
rewriteRelativeImportExtensions: true,
|
|
888
|
-
erasableSyntaxOnly: true
|
|
923
|
+
erasableSyntaxOnly: true,
|
|
924
|
+
noEmit: true
|
|
889
925
|
},
|
|
890
926
|
include: ["../*.config.ts", "./*.ts"]
|
|
891
927
|
};
|
|
@@ -917,6 +953,7 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
917
953
|
composite: true,
|
|
918
954
|
rewriteRelativeImportExtensions: true,
|
|
919
955
|
erasableSyntaxOnly: true,
|
|
956
|
+
noEmit: true,
|
|
920
957
|
...isReact || isR3f ? { jsx: "react-jsx" } : {}
|
|
921
958
|
},
|
|
922
959
|
include: ["src", "tests"]
|
|
@@ -938,7 +975,8 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
938
975
|
skipLibCheck: true,
|
|
939
976
|
composite: true,
|
|
940
977
|
rewriteRelativeImportExtensions: true,
|
|
941
|
-
erasableSyntaxOnly: true
|
|
978
|
+
erasableSyntaxOnly: true,
|
|
979
|
+
noEmit: true
|
|
942
980
|
},
|
|
943
981
|
include: ["*.config.ts"]
|
|
944
982
|
};
|
|
@@ -950,8 +988,108 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
950
988
|
return { files, devDependencies };
|
|
951
989
|
}
|
|
952
990
|
|
|
991
|
+
const packageJsonScripts = {
|
|
992
|
+
appBase: {
|
|
993
|
+
dev: "vite",
|
|
994
|
+
build: "vite build"
|
|
995
|
+
},
|
|
996
|
+
typescript: {
|
|
997
|
+
typecheck: "tsc --build --noEmit",
|
|
998
|
+
"typecheck:watch": "tsc --build --watch"
|
|
999
|
+
},
|
|
1000
|
+
test: {
|
|
1001
|
+
vitest: {
|
|
1002
|
+
test: "vitest"
|
|
1003
|
+
}
|
|
1004
|
+
},
|
|
1005
|
+
build: {
|
|
1006
|
+
unbuild(configPath) {
|
|
1007
|
+
return {
|
|
1008
|
+
build: configPath == null ? "unbuild" : `unbuild --config ${configPath}`
|
|
1009
|
+
};
|
|
1010
|
+
},
|
|
1011
|
+
tsdown: {
|
|
1012
|
+
build: "tsdown"
|
|
1013
|
+
}
|
|
1014
|
+
},
|
|
1015
|
+
lint: {
|
|
1016
|
+
oxlint(configPath) {
|
|
1017
|
+
return {
|
|
1018
|
+
lint: configPath == null ? "oxlint" : `oxlint -c ${configPath}`
|
|
1019
|
+
};
|
|
1020
|
+
},
|
|
1021
|
+
eslint(configPath) {
|
|
1022
|
+
return {
|
|
1023
|
+
lint: configPath == null ? "eslint ." : `eslint --config ${configPath} .`
|
|
1024
|
+
};
|
|
1025
|
+
},
|
|
1026
|
+
biome(configPath) {
|
|
1027
|
+
return {
|
|
1028
|
+
lint: configPath == null ? "biome lint ." : `biome lint --config-path ${configPath} .`
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
},
|
|
1032
|
+
format: {
|
|
1033
|
+
prettier(configPath, ignorePath) {
|
|
1034
|
+
const configFlag = configPath == null ? "" : ` --config ${configPath}`;
|
|
1035
|
+
const ignoreFlag = ignorePath == null ? "" : ` --ignore-path ${ignorePath}`;
|
|
1036
|
+
return {
|
|
1037
|
+
format: `prettier${configFlag}${ignoreFlag} --write .`
|
|
1038
|
+
};
|
|
1039
|
+
},
|
|
1040
|
+
oxfmt(configPath) {
|
|
1041
|
+
return {
|
|
1042
|
+
format: `oxfmt -c ${configPath} --write .`
|
|
1043
|
+
};
|
|
1044
|
+
},
|
|
1045
|
+
biome(configPath) {
|
|
1046
|
+
return {
|
|
1047
|
+
format: configPath == null ? "biome format --write ." : `biome format --config-path ${configPath} --write .`
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
},
|
|
1051
|
+
release(packageManagerName) {
|
|
1052
|
+
return {
|
|
1053
|
+
release: `${packageManagerName} run build && ${packageManagerName} publish`
|
|
1054
|
+
};
|
|
1055
|
+
},
|
|
1056
|
+
monorepoRoot(linter, formatter) {
|
|
1057
|
+
return mergePackageJsonScripts(
|
|
1058
|
+
{
|
|
1059
|
+
dev: "pnpm --filter './apps/*' run dev",
|
|
1060
|
+
build: "pnpm --filter './packages/*' run build && pnpm --filter './apps/*' run build",
|
|
1061
|
+
test: "pnpm -r run test"
|
|
1062
|
+
},
|
|
1063
|
+
linter === "oxlint" ? {
|
|
1064
|
+
lint: "oxlint ."
|
|
1065
|
+
} : linter === "biome" ? {
|
|
1066
|
+
lint: "biome check ."
|
|
1067
|
+
} : {
|
|
1068
|
+
lint: "eslint ."
|
|
1069
|
+
},
|
|
1070
|
+
formatter === "oxfmt" ? {
|
|
1071
|
+
format: "oxfmt -c .config/oxfmt/base.json ."
|
|
1072
|
+
} : formatter === "biome" ? {
|
|
1073
|
+
format: "biome format . --write"
|
|
1074
|
+
} : {
|
|
1075
|
+
format: "prettier --config .config/prettier/base.json --ignore-path .config/prettier/prettierignore --write ."
|
|
1076
|
+
}
|
|
1077
|
+
);
|
|
1078
|
+
}
|
|
1079
|
+
};
|
|
1080
|
+
function mergePackageJsonScripts(...scriptSets) {
|
|
1081
|
+
return Object.assign({}, ...scriptSets.filter((scriptSet) => scriptSet != null));
|
|
1082
|
+
}
|
|
1083
|
+
function resolveDefaultPackageJsonScripts(params) {
|
|
1084
|
+
return mergePackageJsonScripts(
|
|
1085
|
+
params.isLibrary ? void 0 : packageJsonScripts.appBase,
|
|
1086
|
+
params.language === "typescript" ? packageJsonScripts.typescript : void 0,
|
|
1087
|
+
params.isLibrary ? packageJsonScripts.release(params.packageManagerName) : void 0
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
953
1091
|
const DEFAULT_LIBRARY_VERSION = "0.1.0";
|
|
954
|
-
function
|
|
1092
|
+
function renderPackageJson(params) {
|
|
955
1093
|
const {
|
|
956
1094
|
name,
|
|
957
1095
|
language,
|
|
@@ -959,13 +1097,20 @@ function generatePackageJson(params) {
|
|
|
959
1097
|
dependencies,
|
|
960
1098
|
devDependencies,
|
|
961
1099
|
peerDependencies,
|
|
962
|
-
scripts,
|
|
963
1100
|
options,
|
|
964
1101
|
workspaceDependencies
|
|
965
1102
|
} = params;
|
|
966
1103
|
const files = {};
|
|
967
1104
|
const packageManager = getPackageManagerSpec(options.packageManager);
|
|
968
1105
|
const isPnpm = packageManager.name === "pnpm";
|
|
1106
|
+
const resolvedScripts = mergePackageJsonScripts(
|
|
1107
|
+
resolveDefaultPackageJsonScripts({
|
|
1108
|
+
language,
|
|
1109
|
+
isLibrary,
|
|
1110
|
+
packageManagerName: packageManager.name
|
|
1111
|
+
}),
|
|
1112
|
+
params.scripts
|
|
1113
|
+
);
|
|
969
1114
|
const packageJson = {
|
|
970
1115
|
name,
|
|
971
1116
|
description: "Built with \u{1F339} create-krispya",
|
|
@@ -997,12 +1142,9 @@ function generatePackageJson(params) {
|
|
|
997
1142
|
const allDevDependencies = { ...devDependencies };
|
|
998
1143
|
const engine = getEngineSpec(options.engine);
|
|
999
1144
|
if (getEngineName(engine) === "node" && engine.version) {
|
|
1000
|
-
allDevDependencies["@types/node"] ??= formatNodeTypesVersion(
|
|
1001
|
-
options.versions,
|
|
1002
|
-
options.engine
|
|
1003
|
-
);
|
|
1145
|
+
allDevDependencies["@types/node"] ??= formatNodeTypesVersion(options.versions, options.engine);
|
|
1004
1146
|
}
|
|
1005
|
-
packageJson.scripts =
|
|
1147
|
+
packageJson.scripts = resolvedScripts;
|
|
1006
1148
|
packageJson.dependencies = sortKeys(allDependencies);
|
|
1007
1149
|
if (Object.keys(allDevDependencies).length > 0) {
|
|
1008
1150
|
packageJson.devDependencies = sortKeys(allDevDependencies);
|
|
@@ -1045,7 +1187,7 @@ function generatePackageJson(params) {
|
|
|
1045
1187
|
return { files };
|
|
1046
1188
|
}
|
|
1047
1189
|
|
|
1048
|
-
function
|
|
1190
|
+
function renderReadme(params) {
|
|
1049
1191
|
const { name, baseTemplate, isLibrary, libraryBundler, packageManager, codeSnippets } = params;
|
|
1050
1192
|
const isVanilla = baseTemplate === "vanilla";
|
|
1051
1193
|
const isReact = baseTemplate === "react";
|
|
@@ -1101,13 +1243,14 @@ function generateReadme(params) {
|
|
|
1101
1243
|
} else if (isReact) {
|
|
1102
1244
|
architectureDesc = [
|
|
1103
1245
|
`- \`src/app.${jsxExt}\` defines the main application component`,
|
|
1104
|
-
`- \`src/
|
|
1246
|
+
`- \`src/main.${jsxExt}\` renders the React app into the DOM`,
|
|
1105
1247
|
`- \`tests/\` contains your test files`,
|
|
1106
1248
|
`- Static assets can be placed in the \`public\` folder`
|
|
1107
1249
|
];
|
|
1108
1250
|
} else {
|
|
1109
1251
|
architectureDesc = [
|
|
1110
|
-
`- \`app.${jsxExt}\` defines the main application component containing your 3D content`,
|
|
1252
|
+
`- \`src/app.${jsxExt}\` defines the main application component containing your 3D content`,
|
|
1253
|
+
`- \`src/main.${jsxExt}\` renders the React app into the DOM`,
|
|
1111
1254
|
`- Modify the content inside the \`<Canvas>\` component to change what is visible on screen`,
|
|
1112
1255
|
`- \`tests/\` contains your test files`,
|
|
1113
1256
|
`- Static assets can be placed in the \`public\` folder`
|
|
@@ -1138,7 +1281,67 @@ function generateReadme(params) {
|
|
|
1138
1281
|
return { type: "text", content };
|
|
1139
1282
|
}
|
|
1140
1283
|
|
|
1141
|
-
|
|
1284
|
+
const htmlContent = `<!DOCTYPE html>
|
|
1285
|
+
<html lang="en">
|
|
1286
|
+
<head>
|
|
1287
|
+
<meta charset="UTF-8">
|
|
1288
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1289
|
+
<title>$title</title>
|
|
1290
|
+
</head>
|
|
1291
|
+
<body>
|
|
1292
|
+
<div id="root"></div>
|
|
1293
|
+
<script type="module" src="$indexPath"><\/script>
|
|
1294
|
+
</body>
|
|
1295
|
+
</html>`;
|
|
1296
|
+
const viteHtmlContent = `<!DOCTYPE html>
|
|
1297
|
+
<html lang="en">
|
|
1298
|
+
<head>
|
|
1299
|
+
<meta charset="UTF-8">
|
|
1300
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1301
|
+
<title>$title</title>
|
|
1302
|
+
</head>
|
|
1303
|
+
<body>
|
|
1304
|
+
<div id="app"></div>
|
|
1305
|
+
<script type="module" src="$indexPath"><\/script>
|
|
1306
|
+
</body>
|
|
1307
|
+
</html>`;
|
|
1308
|
+
const indexContent = `import { StrictMode } from 'react'
|
|
1309
|
+
import { createRoot } from 'react-dom/client'
|
|
1310
|
+
import './index.css'
|
|
1311
|
+
import { App } from './app.js'
|
|
1312
|
+
|
|
1313
|
+
createRoot(document.getElementById('root')!).render(
|
|
1314
|
+
<StrictMode>
|
|
1315
|
+
<App />
|
|
1316
|
+
</StrictMode>,
|
|
1317
|
+
)`;
|
|
1318
|
+
const viteIndexContent = `import './index.css'
|
|
1319
|
+
|
|
1320
|
+
document.querySelector('#app')!.innerHTML = \`
|
|
1321
|
+
<h1>Hello Vite!</h1>
|
|
1322
|
+
<p>Edit src/main.ts and save to see HMR in action.</p>
|
|
1323
|
+
\``;
|
|
1324
|
+
const viteStyleContent = `:root {
|
|
1325
|
+
font-family:
|
|
1326
|
+
system-ui,
|
|
1327
|
+
-apple-system,
|
|
1328
|
+
sans-serif;
|
|
1329
|
+
line-height: 1.5;
|
|
1330
|
+
font-weight: 400;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
*,
|
|
1334
|
+
*::before,
|
|
1335
|
+
*::after {
|
|
1336
|
+
box-sizing: border-box;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
body {
|
|
1340
|
+
margin: 0;
|
|
1341
|
+
}`;
|
|
1342
|
+
const viteEnvContent = `/// <reference types="vite/client" />`;
|
|
1343
|
+
|
|
1344
|
+
function renderSourceFiles(params) {
|
|
1142
1345
|
const { name, baseTemplate, language, isLibrary, codeSnippets, replacements } = params;
|
|
1143
1346
|
const files = {};
|
|
1144
1347
|
const ext = language === "typescript" ? "ts" : "js";
|
|
@@ -1146,6 +1349,9 @@ function generateSourceFiles(params) {
|
|
|
1146
1349
|
const isVanilla = baseTemplate === "vanilla";
|
|
1147
1350
|
const isReact = baseTemplate === "react";
|
|
1148
1351
|
const isR3f = baseTemplate === "r3f";
|
|
1352
|
+
if (!isLibrary && language === "typescript") {
|
|
1353
|
+
files["src/vite-env.d.ts"] = { type: "text", content: viteEnvContent };
|
|
1354
|
+
}
|
|
1149
1355
|
if (isLibrary) {
|
|
1150
1356
|
const libExt = isReact || isR3f ? jsxExt : ext;
|
|
1151
1357
|
let libContent;
|
|
@@ -1178,19 +1384,20 @@ function generateSourceFiles(params) {
|
|
|
1178
1384
|
}
|
|
1179
1385
|
files[`src/index.${libExt}`] = { type: "text", content: libContent };
|
|
1180
1386
|
} else if (isVanilla) {
|
|
1181
|
-
files[`src/main.${ext}`] = { type: "text", content:
|
|
1182
|
-
files["src/
|
|
1183
|
-
const indexHtml =
|
|
1184
|
-
"$title",
|
|
1185
|
-
name
|
|
1186
|
-
);
|
|
1387
|
+
files[`src/main.${ext}`] = { type: "text", content: viteIndexContent };
|
|
1388
|
+
files["src/index.css"] = { type: "text", content: viteStyleContent };
|
|
1389
|
+
const indexHtml = viteHtmlContent.replace("$indexPath", `./src/main.${ext}`).replace("$title", name);
|
|
1187
1390
|
files["index.html"] = { type: "text", content: indexHtml };
|
|
1188
1391
|
} else {
|
|
1189
|
-
files[`src/
|
|
1190
|
-
|
|
1191
|
-
"
|
|
1192
|
-
|
|
1193
|
-
|
|
1392
|
+
files[`src/main.${jsxExt}`] = {
|
|
1393
|
+
type: "text",
|
|
1394
|
+
content: language === "typescript" ? indexContent : indexContent.replace(
|
|
1395
|
+
"document.getElementById('root')!",
|
|
1396
|
+
"document.getElementById('root')"
|
|
1397
|
+
)
|
|
1398
|
+
};
|
|
1399
|
+
files["src/index.css"] = { type: "text", content: viteStyleContent };
|
|
1400
|
+
const indexHtml = htmlContent.replace("$indexPath", `./src/main.${jsxExt}`).replace("$title", name);
|
|
1194
1401
|
files["index.html"] = { type: "text", content: indexHtml };
|
|
1195
1402
|
codeSnippets["dom-end"]?.reverse();
|
|
1196
1403
|
codeSnippets["global-end"]?.reverse();
|
|
@@ -1232,12 +1439,12 @@ function generateSourceFiles(params) {
|
|
|
1232
1439
|
for (const { search, replace } of replacements) {
|
|
1233
1440
|
appCode = appCode.replace(search, replace);
|
|
1234
1441
|
}
|
|
1235
|
-
files[`src/app
|
|
1442
|
+
files[`src/app.${jsxExt}`] = { type: "text", content: appCode };
|
|
1236
1443
|
}
|
|
1237
1444
|
return files;
|
|
1238
1445
|
}
|
|
1239
1446
|
|
|
1240
|
-
function
|
|
1447
|
+
function renderTestFiles(params) {
|
|
1241
1448
|
const { baseTemplate, language, isLibrary } = params;
|
|
1242
1449
|
const files = {};
|
|
1243
1450
|
const ext = language === "typescript" ? "ts" : "js";
|
|
@@ -1344,21 +1551,184 @@ const COMMON_GITIGNORE_LINES = [
|
|
|
1344
1551
|
"*.tsbuildinfo",
|
|
1345
1552
|
".env",
|
|
1346
1553
|
".env.*",
|
|
1347
|
-
"!.env.example"
|
|
1554
|
+
"!.env.example",
|
|
1555
|
+
".pnpm-store"
|
|
1348
1556
|
];
|
|
1349
|
-
function
|
|
1557
|
+
function renderGitignore(variant) {
|
|
1350
1558
|
const lines = variant === "workspace-root" ? [...COMMON_GITIGNORE_LINES, ".DS_Store"] : COMMON_GITIGNORE_LINES;
|
|
1351
1559
|
return {
|
|
1352
1560
|
type: "text",
|
|
1353
1561
|
content: lines.join("\n")
|
|
1354
1562
|
};
|
|
1355
1563
|
}
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1564
|
+
|
|
1565
|
+
const defaultFormatterMetaConfig = {
|
|
1566
|
+
printWidth: 102,
|
|
1567
|
+
tabWidth: 2,
|
|
1568
|
+
useTabs: false,
|
|
1569
|
+
semi: true,
|
|
1570
|
+
singleQuote: true,
|
|
1571
|
+
trailingComma: "es5",
|
|
1572
|
+
bracketSpacing: true,
|
|
1573
|
+
arrowParens: "always",
|
|
1574
|
+
ignorePatterns: [
|
|
1575
|
+
"package-lock.json",
|
|
1576
|
+
"npm-shrinkwrap.json",
|
|
1577
|
+
"pnpm-lock.yaml",
|
|
1578
|
+
"pnpm-lock.json",
|
|
1579
|
+
"yarn.lock",
|
|
1580
|
+
"bun.lock",
|
|
1581
|
+
"bun.lockb"
|
|
1582
|
+
]
|
|
1583
|
+
};
|
|
1584
|
+
|
|
1585
|
+
function renderEditorConfig(config = defaultFormatterMetaConfig) {
|
|
1586
|
+
const indentStyle = config.useTabs ? "tab" : "space";
|
|
1587
|
+
const indentSize = config.useTabs ? "tab" : String(config.tabWidth);
|
|
1588
|
+
return {
|
|
1589
|
+
type: "text",
|
|
1590
|
+
content: [
|
|
1591
|
+
"root = true",
|
|
1592
|
+
"",
|
|
1593
|
+
"[*]",
|
|
1594
|
+
"charset = utf-8",
|
|
1595
|
+
"end_of_line = lf",
|
|
1596
|
+
"insert_final_newline = true",
|
|
1597
|
+
`indent_style = ${indentStyle}`,
|
|
1598
|
+
`indent_size = ${indentSize}`,
|
|
1599
|
+
`tab_width = ${config.tabWidth}`,
|
|
1600
|
+
`max_line_length = ${config.printWidth}`
|
|
1601
|
+
].join("\n")
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1604
|
+
function renderVscodeEditorSettings(config = defaultFormatterMetaConfig) {
|
|
1605
|
+
return {
|
|
1606
|
+
"editor.detectIndentation": false,
|
|
1607
|
+
"editor.insertSpaces": !config.useTabs,
|
|
1608
|
+
"editor.tabSize": config.tabWidth,
|
|
1609
|
+
"files.eol": "\n",
|
|
1610
|
+
"files.insertFinalNewline": true
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
const DEFAULT_VSCODE_SETTINGS = {
|
|
1615
|
+
...renderVscodeEditorSettings(),
|
|
1616
|
+
"explorer.fileNesting.enabled": true,
|
|
1617
|
+
"explorer.fileNesting.expand": false,
|
|
1618
|
+
"explorer.fileNesting.patterns": {
|
|
1619
|
+
".gitignore": ".gitattributes",
|
|
1620
|
+
"AGENTS.md": "CLAUDE.md"
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1623
|
+
const OXFMT_LANGUAGE_SETTINGS = {
|
|
1624
|
+
"[json]": {
|
|
1625
|
+
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1626
|
+
},
|
|
1627
|
+
"[jsonc]": {
|
|
1628
|
+
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1629
|
+
},
|
|
1630
|
+
"[markdown]": {
|
|
1631
|
+
"editor.defaultFormatter": "vscode.markdown-language-features"
|
|
1632
|
+
},
|
|
1633
|
+
"[yaml]": {
|
|
1634
|
+
"editor.defaultFormatter": "redhat.vscode-yaml"
|
|
1635
|
+
}
|
|
1636
|
+
};
|
|
1637
|
+
function resolvePackageJsonNestedFiles(packageManager) {
|
|
1638
|
+
if (packageManager === "pnpm") {
|
|
1639
|
+
return ["pnpm-lock.yaml", "pnpm-workspace.yaml"];
|
|
1640
|
+
}
|
|
1641
|
+
if (packageManager === "npm") {
|
|
1642
|
+
return ["package-lock.json", "npm-shrinkwrap.json"];
|
|
1643
|
+
}
|
|
1644
|
+
if (packageManager === "yarn") {
|
|
1645
|
+
return ["yarn.lock"];
|
|
1646
|
+
}
|
|
1647
|
+
return [];
|
|
1648
|
+
}
|
|
1649
|
+
function resolveVscodeRecommendations(linter, formatter) {
|
|
1650
|
+
const recommendations = [];
|
|
1651
|
+
if (linter === "oxlint" || formatter === "oxfmt") {
|
|
1652
|
+
recommendations.push("oxc.oxc-vscode");
|
|
1653
|
+
}
|
|
1654
|
+
if (linter === "eslint") {
|
|
1655
|
+
recommendations.push("dbaeumer.vscode-eslint");
|
|
1656
|
+
}
|
|
1657
|
+
if (linter === "biome" || formatter === "biome") {
|
|
1658
|
+
recommendations.push("biomejs.biome");
|
|
1659
|
+
}
|
|
1660
|
+
if (formatter === "prettier") {
|
|
1661
|
+
recommendations.push("esbenp.prettier-vscode");
|
|
1662
|
+
}
|
|
1663
|
+
return recommendations;
|
|
1664
|
+
}
|
|
1665
|
+
function resolveVscodeSettings(params) {
|
|
1666
|
+
const { linter, formatter, configStrategy, isMonorepo, packageManager } = params;
|
|
1667
|
+
const settings = { ...DEFAULT_VSCODE_SETTINGS };
|
|
1668
|
+
const isStealth = !isMonorepo && (configStrategy ?? "stealth") === "stealth";
|
|
1669
|
+
const packageJsonNestedFiles = resolvePackageJsonNestedFiles(packageManager);
|
|
1670
|
+
if (packageJsonNestedFiles.length > 0) {
|
|
1671
|
+
settings["explorer.fileNesting.patterns"] = {
|
|
1672
|
+
...settings["explorer.fileNesting.patterns"],
|
|
1673
|
+
"package.json": packageJsonNestedFiles.join(", ")
|
|
1674
|
+
};
|
|
1675
|
+
}
|
|
1676
|
+
if (linter === "eslint") {
|
|
1677
|
+
settings["eslint.enable"] = true;
|
|
1678
|
+
settings["oxc.enable"] = false;
|
|
1679
|
+
settings["biome.enabled"] = false;
|
|
1680
|
+
if (isStealth) {
|
|
1681
|
+
settings["eslint.options"] = {
|
|
1682
|
+
overrideConfigFile: ".config/eslint.config.js"
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1685
|
+
} else if (linter === "oxlint") {
|
|
1686
|
+
settings["oxc.enable"] = true;
|
|
1687
|
+
settings["eslint.enable"] = false;
|
|
1688
|
+
settings["biome.enabled"] = false;
|
|
1689
|
+
if (isStealth) {
|
|
1690
|
+
settings["oxc.configPath"] = ".config/oxlint.json";
|
|
1691
|
+
}
|
|
1692
|
+
} else if (linter === "biome") {
|
|
1693
|
+
settings["biome.enabled"] = true;
|
|
1694
|
+
settings["eslint.enable"] = false;
|
|
1695
|
+
settings["oxc.enable"] = false;
|
|
1696
|
+
if (isStealth) {
|
|
1697
|
+
settings["biome.linter.configPath"] = ".config/biome.json";
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
if (formatter === "prettier") {
|
|
1701
|
+
settings["editor.defaultFormatter"] = "esbenp.prettier-vscode";
|
|
1702
|
+
if (isStealth) {
|
|
1703
|
+
settings["prettier.configPath"] = ".config/prettier.json";
|
|
1704
|
+
settings["prettier.ignorePath"] = ".config/prettierignore";
|
|
1705
|
+
}
|
|
1706
|
+
} else if (formatter === "oxfmt") {
|
|
1707
|
+
settings["editor.defaultFormatter"] = "oxc.oxc-vscode";
|
|
1708
|
+
Object.assign(settings, OXFMT_LANGUAGE_SETTINGS);
|
|
1709
|
+
if (isStealth) {
|
|
1710
|
+
settings["oxc.fmt.configPath"] = ".config/oxfmt.json";
|
|
1711
|
+
}
|
|
1712
|
+
} else if (formatter === "biome") {
|
|
1713
|
+
settings["biome.enabled"] = true;
|
|
1714
|
+
settings["eslint.enable"] = false;
|
|
1715
|
+
settings["oxc.enable"] = false;
|
|
1716
|
+
settings["editor.defaultFormatter"] = "biomejs.biome";
|
|
1717
|
+
if (isStealth) {
|
|
1718
|
+
settings["biome.linter.configPath"] = ".config/biome.json";
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
return settings;
|
|
1722
|
+
}
|
|
1723
|
+
function renderVscodeFiles$1(params) {
|
|
1724
|
+
const { codeSnippets = {}, vscodeSettings = {} } = params;
|
|
1359
1725
|
const files = {};
|
|
1360
|
-
|
|
1361
|
-
|
|
1726
|
+
const recommendations = [
|
|
1727
|
+
...codeSnippets["vscode-extension-suggestion"] ?? [],
|
|
1728
|
+
...resolveVscodeRecommendations(params.linter, params.formatter)
|
|
1729
|
+
];
|
|
1730
|
+
if (recommendations.length > 0) {
|
|
1731
|
+
const uniqueRecommendations = [...new Set(recommendations)];
|
|
1362
1732
|
files[".vscode/extensions.json"] = {
|
|
1363
1733
|
type: "text",
|
|
1364
1734
|
content: JSON.stringify(
|
|
@@ -1370,9 +1740,13 @@ function generateVscodeFiles$1(params) {
|
|
|
1370
1740
|
)
|
|
1371
1741
|
};
|
|
1372
1742
|
}
|
|
1373
|
-
|
|
1743
|
+
const resolvedSettings = {
|
|
1744
|
+
...resolveVscodeSettings(params),
|
|
1745
|
+
...vscodeSettings
|
|
1746
|
+
};
|
|
1747
|
+
if (Object.keys(resolvedSettings).length > 0) {
|
|
1374
1748
|
const sortedSettings = Object.fromEntries(
|
|
1375
|
-
Object.entries(
|
|
1749
|
+
Object.entries(resolvedSettings).sort(([a], [b]) => a.localeCompare(b))
|
|
1376
1750
|
);
|
|
1377
1751
|
files[".vscode/settings.json"] = {
|
|
1378
1752
|
type: "text",
|
|
@@ -1389,7 +1763,7 @@ function formatValue(value, indent) {
|
|
|
1389
1763
|
if (value.startsWith("$raw:")) {
|
|
1390
1764
|
return value.slice(5);
|
|
1391
1765
|
}
|
|
1392
|
-
return
|
|
1766
|
+
return `'${value.replaceAll("\\", "\\\\").replaceAll("'", "\\'")}'`;
|
|
1393
1767
|
}
|
|
1394
1768
|
if (typeof value === "number" || typeof value === "boolean") {
|
|
1395
1769
|
return String(value);
|
|
@@ -1397,8 +1771,17 @@ function formatValue(value, indent) {
|
|
|
1397
1771
|
if (value === null) {
|
|
1398
1772
|
return "null";
|
|
1399
1773
|
}
|
|
1774
|
+
if (value === void 0) {
|
|
1775
|
+
return "undefined";
|
|
1776
|
+
}
|
|
1777
|
+
if (typeof value === "bigint") {
|
|
1778
|
+
return value.toString();
|
|
1779
|
+
}
|
|
1400
1780
|
if (Array.isArray(value)) {
|
|
1401
1781
|
if (value.length === 0) return "[]";
|
|
1782
|
+
if (value.every((item) => item == null || typeof item !== "object")) {
|
|
1783
|
+
return `[${value.map((item) => formatValue(item, indent + 1)).join(", ")}]`;
|
|
1784
|
+
}
|
|
1402
1785
|
const items = value.map((v) => `${innerSpaces}${formatValue(v, indent + 1)}`);
|
|
1403
1786
|
return `[
|
|
1404
1787
|
${items.join(",\n")}
|
|
@@ -1408,28 +1791,114 @@ ${spaces}]`;
|
|
|
1408
1791
|
const entries = Object.entries(value);
|
|
1409
1792
|
if (entries.length === 0) return "{}";
|
|
1410
1793
|
const props = entries.map(
|
|
1411
|
-
([key, val]) => `${innerSpaces}${key}: ${formatValue(val, indent + 1)}
|
|
1794
|
+
([key, val]) => `${innerSpaces}${key}: ${formatValue(val, indent + 1)},`
|
|
1412
1795
|
);
|
|
1413
1796
|
return `{
|
|
1414
|
-
${props.join("
|
|
1797
|
+
${props.join("\n")}
|
|
1415
1798
|
${spaces}}`;
|
|
1416
1799
|
}
|
|
1417
|
-
|
|
1800
|
+
throw new TypeError(`Unsupported vite config value type: ${typeof value}`);
|
|
1418
1801
|
}
|
|
1419
|
-
function
|
|
1802
|
+
function renderViteConfig(params) {
|
|
1420
1803
|
const { viteConfig, codeSnippets } = params;
|
|
1421
1804
|
const configBody = formatValue(viteConfig, 0);
|
|
1422
1805
|
const viteConfigContent = [
|
|
1423
|
-
`import { defineConfig } from
|
|
1806
|
+
`import { defineConfig } from 'vite';`,
|
|
1424
1807
|
...codeSnippets["vite-config-import"] ?? [],
|
|
1425
1808
|
``,
|
|
1426
|
-
`export default defineConfig(${configBody})
|
|
1809
|
+
`export default defineConfig(${configBody});`,
|
|
1427
1810
|
``
|
|
1428
1811
|
].join("\n");
|
|
1429
1812
|
return { type: "text", content: viteConfigContent };
|
|
1430
1813
|
}
|
|
1431
1814
|
|
|
1432
|
-
function
|
|
1815
|
+
function toPrettierConfig(config = defaultFormatterMetaConfig) {
|
|
1816
|
+
return {
|
|
1817
|
+
$schema: "https://json.schemastore.org/prettierrc",
|
|
1818
|
+
printWidth: config.printWidth,
|
|
1819
|
+
tabWidth: config.tabWidth,
|
|
1820
|
+
useTabs: config.useTabs,
|
|
1821
|
+
semi: config.semi,
|
|
1822
|
+
singleQuote: config.singleQuote,
|
|
1823
|
+
trailingComma: config.trailingComma,
|
|
1824
|
+
bracketSpacing: config.bracketSpacing,
|
|
1825
|
+
arrowParens: config.arrowParens,
|
|
1826
|
+
overrides: [
|
|
1827
|
+
{
|
|
1828
|
+
files: ["*.md", "**/*.md"],
|
|
1829
|
+
options: { semi: false }
|
|
1830
|
+
},
|
|
1831
|
+
{
|
|
1832
|
+
files: ["*.yml", "*.yaml", "**/*.yml", "**/*.yaml"],
|
|
1833
|
+
options: { semi: false }
|
|
1834
|
+
}
|
|
1835
|
+
]
|
|
1836
|
+
};
|
|
1837
|
+
}
|
|
1838
|
+
function toPrettierIgnoreContent(config = defaultFormatterMetaConfig) {
|
|
1839
|
+
return config.ignorePatterns.join("\n");
|
|
1840
|
+
}
|
|
1841
|
+
function toOxfmtConfig(config = defaultFormatterMetaConfig) {
|
|
1842
|
+
return {
|
|
1843
|
+
printWidth: config.printWidth,
|
|
1844
|
+
tabWidth: config.tabWidth,
|
|
1845
|
+
useTabs: config.useTabs,
|
|
1846
|
+
semi: config.semi,
|
|
1847
|
+
singleQuote: config.singleQuote,
|
|
1848
|
+
trailingComma: config.trailingComma,
|
|
1849
|
+
bracketSpacing: config.bracketSpacing,
|
|
1850
|
+
arrowParens: config.arrowParens,
|
|
1851
|
+
ignorePatterns: config.ignorePatterns
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
const defaultLinterMetaConfig = {
|
|
1856
|
+
ignorePatterns: ["dist"],
|
|
1857
|
+
rules: {
|
|
1858
|
+
noUnusedVars: {
|
|
1859
|
+
level: "warn",
|
|
1860
|
+
argsIgnorePattern: "^_",
|
|
1861
|
+
varsIgnorePattern: "^_",
|
|
1862
|
+
caughtErrorsIgnorePattern: "^_"
|
|
1863
|
+
},
|
|
1864
|
+
noUnusedExpressions: {
|
|
1865
|
+
level: "warn",
|
|
1866
|
+
allowShortCircuit: true
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
};
|
|
1870
|
+
|
|
1871
|
+
function renderOxlintConfig(params) {
|
|
1872
|
+
const config = params.config ?? defaultLinterMetaConfig;
|
|
1873
|
+
const { rules } = config;
|
|
1874
|
+
const plugins = ["unicorn", "typescript", "oxc"];
|
|
1875
|
+
if (params.react === true) {
|
|
1876
|
+
plugins.push("react");
|
|
1877
|
+
}
|
|
1878
|
+
return {
|
|
1879
|
+
$schema: params.schemaPath,
|
|
1880
|
+
plugins,
|
|
1881
|
+
...params.typescript === true ? { options: { typeAware: true } } : {},
|
|
1882
|
+
rules: {
|
|
1883
|
+
"no-unused-vars": [
|
|
1884
|
+
rules.noUnusedVars.level,
|
|
1885
|
+
{
|
|
1886
|
+
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
1887
|
+
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
1888
|
+
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
1889
|
+
}
|
|
1890
|
+
],
|
|
1891
|
+
"no-useless-escape": "off",
|
|
1892
|
+
"no-unused-expressions": [
|
|
1893
|
+
rules.noUnusedExpressions.level,
|
|
1894
|
+
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
1895
|
+
]
|
|
1896
|
+
},
|
|
1897
|
+
ignorePatterns: config.ignorePatterns
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
function renderTypescriptConfigPackage(files) {
|
|
1433
1902
|
const basePath = ".config/typescript";
|
|
1434
1903
|
files[`${basePath}/package.json`] = {
|
|
1435
1904
|
type: "text",
|
|
@@ -1534,9 +2003,8 @@ In your package's \`tsconfig.json\`:
|
|
|
1534
2003
|
)
|
|
1535
2004
|
};
|
|
1536
2005
|
}
|
|
1537
|
-
function
|
|
2006
|
+
function renderOxlintConfigPackage(files) {
|
|
1538
2007
|
const basePath = ".config/oxlint";
|
|
1539
|
-
const { rules } = defaultLinterConfig;
|
|
1540
2008
|
files[`${basePath}/package.json`] = {
|
|
1541
2009
|
type: "text",
|
|
1542
2010
|
content: JSON.stringify(
|
|
@@ -1573,26 +2041,10 @@ oxlint -c node_modules/@config/oxlint/base.json
|
|
|
1573
2041
|
files[`${basePath}/base.json`] = {
|
|
1574
2042
|
type: "text",
|
|
1575
2043
|
content: JSON.stringify(
|
|
1576
|
-
{
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
"no-unused-vars": [
|
|
1581
|
-
rules.noUnusedVars.level,
|
|
1582
|
-
{
|
|
1583
|
-
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
1584
|
-
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
1585
|
-
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
1586
|
-
}
|
|
1587
|
-
],
|
|
1588
|
-
"no-useless-escape": "off",
|
|
1589
|
-
"no-unused-expressions": [
|
|
1590
|
-
rules.noUnusedExpressions.level,
|
|
1591
|
-
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
1592
|
-
]
|
|
1593
|
-
},
|
|
1594
|
-
ignorePatterns: defaultLinterConfig.ignorePatterns
|
|
1595
|
-
},
|
|
2044
|
+
renderOxlintConfig({
|
|
2045
|
+
schemaPath: "./node_modules/oxlint/configuration_schema.json",
|
|
2046
|
+
typescript: true
|
|
2047
|
+
}),
|
|
1596
2048
|
null,
|
|
1597
2049
|
2
|
|
1598
2050
|
)
|
|
@@ -1600,32 +2052,17 @@ oxlint -c node_modules/@config/oxlint/base.json
|
|
|
1600
2052
|
files[`${basePath}/react.json`] = {
|
|
1601
2053
|
type: "text",
|
|
1602
2054
|
content: JSON.stringify(
|
|
1603
|
-
{
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
rules.noUnusedVars.level,
|
|
1609
|
-
{
|
|
1610
|
-
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
1611
|
-
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
1612
|
-
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
1613
|
-
}
|
|
1614
|
-
],
|
|
1615
|
-
"no-useless-escape": "off",
|
|
1616
|
-
"no-unused-expressions": [
|
|
1617
|
-
rules.noUnusedExpressions.level,
|
|
1618
|
-
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
1619
|
-
]
|
|
1620
|
-
},
|
|
1621
|
-
ignorePatterns: defaultLinterConfig.ignorePatterns
|
|
1622
|
-
},
|
|
2055
|
+
renderOxlintConfig({
|
|
2056
|
+
schemaPath: "./node_modules/oxlint/configuration_schema.json",
|
|
2057
|
+
react: true,
|
|
2058
|
+
typescript: true
|
|
2059
|
+
}),
|
|
1623
2060
|
null,
|
|
1624
2061
|
2
|
|
1625
2062
|
)
|
|
1626
2063
|
};
|
|
1627
2064
|
}
|
|
1628
|
-
function
|
|
2065
|
+
function renderEslintConfigPackage(files) {
|
|
1629
2066
|
const basePath = ".config/eslint";
|
|
1630
2067
|
files[`${basePath}/package.json`] = {
|
|
1631
2068
|
type: "text",
|
|
@@ -1732,7 +2169,7 @@ export default tseslint.config(
|
|
|
1732
2169
|
`
|
|
1733
2170
|
};
|
|
1734
2171
|
}
|
|
1735
|
-
function
|
|
2172
|
+
function renderPrettierConfigPackage(files) {
|
|
1736
2173
|
const basePath = ".config/prettier";
|
|
1737
2174
|
files[`${basePath}/package.json`] = {
|
|
1738
2175
|
type: "text",
|
|
@@ -1745,7 +2182,7 @@ function generatePrettierConfigPackage(files) {
|
|
|
1745
2182
|
exports: {
|
|
1746
2183
|
".": "./base.json"
|
|
1747
2184
|
},
|
|
1748
|
-
files: ["base.json"]
|
|
2185
|
+
files: ["base.json", "prettierignore"]
|
|
1749
2186
|
},
|
|
1750
2187
|
null,
|
|
1751
2188
|
2
|
|
@@ -1780,10 +2217,14 @@ Or in \`.prettierrc.json\`:
|
|
|
1780
2217
|
};
|
|
1781
2218
|
files[`${basePath}/base.json`] = {
|
|
1782
2219
|
type: "text",
|
|
1783
|
-
content: JSON.stringify(
|
|
2220
|
+
content: JSON.stringify(toPrettierConfig(), null, 2)
|
|
2221
|
+
};
|
|
2222
|
+
files[`${basePath}/prettierignore`] = {
|
|
2223
|
+
type: "text",
|
|
2224
|
+
content: toPrettierIgnoreContent()
|
|
1784
2225
|
};
|
|
1785
2226
|
}
|
|
1786
|
-
function
|
|
2227
|
+
function renderOxfmtConfigPackage(files) {
|
|
1787
2228
|
const basePath = ".config/oxfmt";
|
|
1788
2229
|
files[`${basePath}/package.json`] = {
|
|
1789
2230
|
type: "text",
|
|
@@ -1819,11 +2260,11 @@ oxfmt -c node_modules/@config/oxfmt/base.json --write .
|
|
|
1819
2260
|
};
|
|
1820
2261
|
files[`${basePath}/base.json`] = {
|
|
1821
2262
|
type: "text",
|
|
1822
|
-
content: JSON.stringify(
|
|
2263
|
+
content: JSON.stringify(toOxfmtConfig(), null, 2)
|
|
1823
2264
|
};
|
|
1824
2265
|
}
|
|
1825
2266
|
|
|
1826
|
-
function
|
|
2267
|
+
function renderMonorepo(params) {
|
|
1827
2268
|
const {
|
|
1828
2269
|
name,
|
|
1829
2270
|
linter,
|
|
@@ -1832,6 +2273,7 @@ function generateMonorepo(params) {
|
|
|
1832
2273
|
pnpmManageVersions,
|
|
1833
2274
|
engine,
|
|
1834
2275
|
versions = {},
|
|
2276
|
+
ide = "vscode",
|
|
1835
2277
|
aiPlatforms
|
|
1836
2278
|
} = params;
|
|
1837
2279
|
const files = {};
|
|
@@ -1844,6 +2286,7 @@ function generateMonorepo(params) {
|
|
|
1844
2286
|
}
|
|
1845
2287
|
if (linter === "oxlint") {
|
|
1846
2288
|
assignResolvedPackageVersion(devDependencies, versions, "oxlint");
|
|
2289
|
+
assignResolvedPackageVersion(devDependencies, versions, "oxlint-tsgolint");
|
|
1847
2290
|
} else if (linter === "eslint") {
|
|
1848
2291
|
assignResolvedPackageVersion(devDependencies, versions, "eslint");
|
|
1849
2292
|
} else if (linter === "biome") {
|
|
@@ -1859,13 +2302,7 @@ function generateMonorepo(params) {
|
|
|
1859
2302
|
version: "0.0.0",
|
|
1860
2303
|
private: true,
|
|
1861
2304
|
type: "module",
|
|
1862
|
-
scripts:
|
|
1863
|
-
dev: "pnpm --filter './apps/*' run dev",
|
|
1864
|
-
build: "pnpm --filter './packages/*' run build && pnpm --filter './apps/*' run build",
|
|
1865
|
-
test: "pnpm -r run test",
|
|
1866
|
-
lint: linter === "oxlint" ? "oxlint ." : linter === "biome" ? "biome check ." : "eslint .",
|
|
1867
|
-
format: formatter === "oxfmt" ? "oxfmt -c .config/oxfmt/base.json ." : formatter === "biome" ? "biome format . --write" : "prettier --config .config/prettier/base.json --write ."
|
|
1868
|
-
},
|
|
2305
|
+
scripts: packageJsonScripts.monorepoRoot(linter, formatter),
|
|
1869
2306
|
devDependencies
|
|
1870
2307
|
};
|
|
1871
2308
|
const engines = {};
|
|
@@ -1911,9 +2348,9 @@ function generateMonorepo(params) {
|
|
|
1911
2348
|
2
|
|
1912
2349
|
)
|
|
1913
2350
|
};
|
|
1914
|
-
|
|
2351
|
+
renderTypescriptConfigPackage(files);
|
|
1915
2352
|
if (linter === "oxlint") {
|
|
1916
|
-
|
|
2353
|
+
renderOxlintConfigPackage(files);
|
|
1917
2354
|
files["oxlint.json"] = {
|
|
1918
2355
|
type: "text",
|
|
1919
2356
|
content: JSON.stringify(
|
|
@@ -1926,7 +2363,7 @@ function generateMonorepo(params) {
|
|
|
1926
2363
|
)
|
|
1927
2364
|
};
|
|
1928
2365
|
} else if (linter === "eslint") {
|
|
1929
|
-
|
|
2366
|
+
renderEslintConfigPackage(files);
|
|
1930
2367
|
files["eslint.config.js"] = {
|
|
1931
2368
|
type: "text",
|
|
1932
2369
|
content: `import base from "@config/eslint/base";
|
|
@@ -1959,11 +2396,12 @@ export default [...base];
|
|
|
1959
2396
|
};
|
|
1960
2397
|
}
|
|
1961
2398
|
if (formatter === "oxfmt") {
|
|
1962
|
-
|
|
2399
|
+
renderOxfmtConfigPackage(files);
|
|
1963
2400
|
} else if (formatter === "prettier") {
|
|
1964
|
-
|
|
2401
|
+
renderPrettierConfigPackage(files);
|
|
1965
2402
|
}
|
|
1966
|
-
files[".
|
|
2403
|
+
files[".editorconfig"] = renderEditorConfig();
|
|
2404
|
+
files[".gitignore"] = renderGitignore("workspace-root");
|
|
1967
2405
|
files[".gitattributes"] = {
|
|
1968
2406
|
type: "text",
|
|
1969
2407
|
content: `* text=auto eol=lf
|
|
@@ -1971,7 +2409,9 @@ export default [...base];
|
|
|
1971
2409
|
*.{bat,[bB][aA][tT]} text eol=crlf
|
|
1972
2410
|
`
|
|
1973
2411
|
};
|
|
1974
|
-
|
|
2412
|
+
if (ide === "vscode") {
|
|
2413
|
+
renderVscodeFiles(files, linter, formatter, packageManager.name);
|
|
2414
|
+
}
|
|
1975
2415
|
files["README.md"] = {
|
|
1976
2416
|
type: "text",
|
|
1977
2417
|
content: `# ${name}
|
|
@@ -1999,104 +2439,50 @@ To add a new package to this workspace, run create-krispya from this directory a
|
|
|
1999
2439
|
`
|
|
2000
2440
|
};
|
|
2001
2441
|
if (aiPlatforms && aiPlatforms.length > 0) {
|
|
2002
|
-
|
|
2442
|
+
renderAiFiles(files, {
|
|
2003
2443
|
name,
|
|
2004
2444
|
packageManager: packageManager.name,
|
|
2005
2445
|
linter,
|
|
2006
2446
|
formatter,
|
|
2007
2447
|
isMonorepo: true,
|
|
2448
|
+
hasTypecheck: false,
|
|
2008
2449
|
platforms: aiPlatforms
|
|
2009
2450
|
});
|
|
2010
2451
|
}
|
|
2011
2452
|
return { files };
|
|
2012
2453
|
}
|
|
2013
|
-
function
|
|
2014
|
-
const recommendations = [];
|
|
2015
|
-
const settings = {};
|
|
2016
|
-
if (linter === "oxlint") {
|
|
2017
|
-
recommendations.push("oxc.oxc-vscode");
|
|
2018
|
-
settings["oxc.enable"] = true;
|
|
2019
|
-
settings["eslint.enable"] = false;
|
|
2020
|
-
settings["biome.enabled"] = false;
|
|
2021
|
-
} else if (linter === "eslint") {
|
|
2022
|
-
recommendations.push("dbaeumer.vscode-eslint");
|
|
2023
|
-
settings["eslint.enable"] = true;
|
|
2024
|
-
settings["oxc.enable"] = false;
|
|
2025
|
-
settings["biome.enabled"] = false;
|
|
2026
|
-
} else if (linter === "biome") {
|
|
2027
|
-
recommendations.push("biomejs.biome");
|
|
2028
|
-
settings["biome.enabled"] = true;
|
|
2029
|
-
settings["eslint.enable"] = false;
|
|
2030
|
-
settings["oxc.enable"] = false;
|
|
2031
|
-
}
|
|
2032
|
-
if (formatter === "oxfmt") {
|
|
2033
|
-
if (!recommendations.includes("oxc.oxc-vscode")) {
|
|
2034
|
-
recommendations.push("oxc.oxc-vscode");
|
|
2035
|
-
}
|
|
2036
|
-
settings["editor.defaultFormatter"] = "oxc.oxc-vscode";
|
|
2037
|
-
settings["[json]"] = {
|
|
2038
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
2039
|
-
};
|
|
2040
|
-
settings["[jsonc]"] = {
|
|
2041
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
2042
|
-
};
|
|
2043
|
-
} else if (formatter === "prettier") {
|
|
2044
|
-
recommendations.push("esbenp.prettier-vscode");
|
|
2045
|
-
settings["editor.defaultFormatter"] = "esbenp.prettier-vscode";
|
|
2046
|
-
} else if (formatter === "biome") {
|
|
2047
|
-
if (!recommendations.includes("biomejs.biome")) {
|
|
2048
|
-
recommendations.push("biomejs.biome");
|
|
2049
|
-
}
|
|
2050
|
-
settings["editor.defaultFormatter"] = "biomejs.biome";
|
|
2051
|
-
}
|
|
2052
|
-
files[".vscode/extensions.json"] = {
|
|
2053
|
-
type: "text",
|
|
2054
|
-
content: JSON.stringify({ recommendations }, null, 2)
|
|
2055
|
-
};
|
|
2056
|
-
const codeSnippets = {};
|
|
2057
|
-
if (recommendations.length > 0) {
|
|
2058
|
-
codeSnippets["vscode-extension-suggestion"] = recommendations;
|
|
2059
|
-
}
|
|
2454
|
+
function renderVscodeFiles(files, linter, formatter, packageManager = "pnpm") {
|
|
2060
2455
|
Object.assign(
|
|
2061
2456
|
files,
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2457
|
+
renderVscodeFiles$1({
|
|
2458
|
+
linter,
|
|
2459
|
+
formatter,
|
|
2460
|
+
isMonorepo: true,
|
|
2461
|
+
packageManager
|
|
2065
2462
|
})
|
|
2066
2463
|
);
|
|
2067
2464
|
}
|
|
2068
2465
|
|
|
2069
|
-
const monorepo = {
|
|
2070
|
-
__proto__: null,
|
|
2071
|
-
generateEslintConfigPackage: generateEslintConfigPackage,
|
|
2072
|
-
generateMonorepo: generateMonorepo,
|
|
2073
|
-
generateOxfmtConfigPackage: generateOxfmtConfigPackage,
|
|
2074
|
-
generateOxlintConfigPackage: generateOxlintConfigPackage,
|
|
2075
|
-
generatePrettierConfigPackage: generatePrettierConfigPackage,
|
|
2076
|
-
generateTypescriptConfigPackage: generateTypescriptConfigPackage,
|
|
2077
|
-
generateVscodeFiles: generateVscodeFiles
|
|
2078
|
-
};
|
|
2079
|
-
|
|
2080
2466
|
function toBiomeLevel(level) {
|
|
2081
2467
|
return level;
|
|
2082
2468
|
}
|
|
2083
|
-
function
|
|
2469
|
+
function planBiome(builder, options) {
|
|
2084
2470
|
if (options == null || !options.linter && !options.formatter) {
|
|
2085
2471
|
return;
|
|
2086
2472
|
}
|
|
2087
|
-
const version =
|
|
2088
|
-
|
|
2089
|
-
const { rules } = defaultLinterConfig;
|
|
2473
|
+
const version = builder.getVersion("@biomejs/biome");
|
|
2474
|
+
builder.addDevDependency("@biomejs/biome");
|
|
2090
2475
|
const biomeConfig = {
|
|
2091
2476
|
$schema: `https://biomejs.dev/schemas/${version}/schema.json`
|
|
2092
2477
|
};
|
|
2093
2478
|
if (options.linter) {
|
|
2479
|
+
const linterConfig = options.linter.config;
|
|
2094
2480
|
biomeConfig.linter = {
|
|
2095
2481
|
enabled: true,
|
|
2096
2482
|
rules: {
|
|
2097
2483
|
recommended: true,
|
|
2098
2484
|
correctness: {
|
|
2099
|
-
noUnusedVariables: toBiomeLevel(rules.noUnusedVars.level)
|
|
2485
|
+
noUnusedVariables: toBiomeLevel(linterConfig.rules.noUnusedVars.level)
|
|
2100
2486
|
}
|
|
2101
2487
|
}
|
|
2102
2488
|
};
|
|
@@ -2106,19 +2492,20 @@ function generateBiome(generator, options) {
|
|
|
2106
2492
|
};
|
|
2107
2493
|
}
|
|
2108
2494
|
if (options.formatter) {
|
|
2495
|
+
const formatterConfig = options.formatter.config;
|
|
2109
2496
|
biomeConfig.formatter = {
|
|
2110
2497
|
enabled: true,
|
|
2111
|
-
lineWidth:
|
|
2112
|
-
indentWidth:
|
|
2113
|
-
indentStyle: "space"
|
|
2498
|
+
lineWidth: formatterConfig.printWidth,
|
|
2499
|
+
indentWidth: formatterConfig.tabWidth,
|
|
2500
|
+
indentStyle: formatterConfig.useTabs ? "tab" : "space"
|
|
2114
2501
|
};
|
|
2115
2502
|
biomeConfig.javascript = {
|
|
2116
2503
|
formatter: {
|
|
2117
|
-
semicolons: "always" ,
|
|
2118
|
-
quoteStyle: "single" ,
|
|
2119
|
-
trailingCommas:
|
|
2120
|
-
bracketSpacing:
|
|
2121
|
-
arrowParentheses: "always"
|
|
2504
|
+
semicolons: formatterConfig.semi ? "always" : "asNeeded",
|
|
2505
|
+
quoteStyle: formatterConfig.singleQuote ? "single" : "double",
|
|
2506
|
+
trailingCommas: formatterConfig.trailingComma,
|
|
2507
|
+
bracketSpacing: formatterConfig.bracketSpacing,
|
|
2508
|
+
arrowParentheses: formatterConfig.arrowParens === "always" ? "always" : "asNeeded"
|
|
2122
2509
|
}
|
|
2123
2510
|
};
|
|
2124
2511
|
biomeConfig.json = {
|
|
@@ -2131,53 +2518,48 @@ function generateBiome(generator, options) {
|
|
|
2131
2518
|
enabled: false
|
|
2132
2519
|
};
|
|
2133
2520
|
}
|
|
2134
|
-
const isStealth =
|
|
2521
|
+
const isStealth = builder.isStealthConfig();
|
|
2135
2522
|
if (isStealth) {
|
|
2136
|
-
|
|
2523
|
+
builder.addFile(".config/biome.json", {
|
|
2137
2524
|
type: "text",
|
|
2138
2525
|
content: JSON.stringify(biomeConfig, null, 2)
|
|
2139
2526
|
});
|
|
2140
2527
|
if (options.linter) {
|
|
2141
|
-
|
|
2528
|
+
builder.addScripts(packageJsonScripts.lint.biome(".config"));
|
|
2142
2529
|
}
|
|
2143
2530
|
if (options.formatter) {
|
|
2144
|
-
|
|
2531
|
+
builder.addScripts(packageJsonScripts.format.biome(".config"));
|
|
2145
2532
|
}
|
|
2146
|
-
generator.addVscodeSetting("biome.linter.configPath", ".config/biome.json");
|
|
2147
2533
|
} else {
|
|
2148
|
-
|
|
2534
|
+
builder.addFile("biome.json", {
|
|
2149
2535
|
type: "text",
|
|
2150
2536
|
content: JSON.stringify(biomeConfig, null, 2)
|
|
2151
2537
|
});
|
|
2152
2538
|
if (options.linter) {
|
|
2153
|
-
|
|
2539
|
+
builder.addScripts(packageJsonScripts.lint.biome());
|
|
2154
2540
|
}
|
|
2155
2541
|
if (options.formatter) {
|
|
2156
|
-
|
|
2542
|
+
builder.addScripts(packageJsonScripts.format.biome());
|
|
2157
2543
|
}
|
|
2158
2544
|
}
|
|
2159
2545
|
const roles = [];
|
|
2160
2546
|
if (options.linter) roles.push("linter");
|
|
2161
2547
|
if (options.formatter) roles.push("formatter");
|
|
2162
|
-
|
|
2548
|
+
builder.inject(
|
|
2163
2549
|
"readme-tools",
|
|
2164
2550
|
`[Biome](https://biomejs.dev/) - Fast ${roles.join(" and ")} for JavaScript and TypeScript`
|
|
2165
2551
|
);
|
|
2166
|
-
|
|
2167
|
-
generator.addVscodeSetting("biome.enabled", true);
|
|
2168
|
-
if (options.formatter) {
|
|
2169
|
-
generator.addVscodeSetting("editor.defaultFormatter", "biomejs.biome");
|
|
2170
|
-
}
|
|
2552
|
+
builder.inject("vscode-extension-suggestion", "biomejs.biome");
|
|
2171
2553
|
}
|
|
2172
2554
|
|
|
2173
|
-
function
|
|
2555
|
+
function planDrei(builder, options) {
|
|
2174
2556
|
if (options == null) {
|
|
2175
2557
|
return;
|
|
2176
2558
|
}
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2559
|
+
builder.addDependency("@react-three/drei");
|
|
2560
|
+
builder.inject("import", `import { Environment } from "@react-three/drei"`);
|
|
2561
|
+
builder.inject("scene", '<Environment background preset="city" />');
|
|
2562
|
+
builder.inject(
|
|
2181
2563
|
"readme-libraries",
|
|
2182
2564
|
`[@react-three/drei](https://drei.docs.pmnd.rs/) - Useful helpers for @react-three/fiber`
|
|
2183
2565
|
);
|
|
@@ -2186,25 +2568,28 @@ function generateDrei(generator, options) {
|
|
|
2186
2568
|
function toEslintLevel(level) {
|
|
2187
2569
|
return level;
|
|
2188
2570
|
}
|
|
2189
|
-
function
|
|
2190
|
-
|
|
2191
|
-
|
|
2571
|
+
function planEslint(builder, options) {
|
|
2572
|
+
if (options == null) {
|
|
2573
|
+
return;
|
|
2574
|
+
}
|
|
2575
|
+
builder.addDevDependency("eslint");
|
|
2576
|
+
const template = builder.options.template ?? "vanilla";
|
|
2192
2577
|
const baseTemplate = getBaseTemplate(template);
|
|
2193
2578
|
const isTypescript = getLanguageFromTemplate(template) === "typescript";
|
|
2194
2579
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2195
|
-
const { rules } =
|
|
2580
|
+
const { rules } = options.config;
|
|
2196
2581
|
const imports = ['import js from "@eslint/js"'];
|
|
2197
2582
|
const configs = ["js.configs.recommended"];
|
|
2198
2583
|
if (isTypescript) {
|
|
2199
|
-
|
|
2584
|
+
builder.addDevDependency("typescript-eslint");
|
|
2200
2585
|
imports.push('import tseslint from "typescript-eslint"');
|
|
2201
2586
|
configs.push("...tseslint.configs.recommended");
|
|
2202
2587
|
}
|
|
2203
2588
|
if (isReact) {
|
|
2204
|
-
|
|
2589
|
+
builder.addDevDependency("eslint-plugin-react-hooks");
|
|
2205
2590
|
imports.push('import reactHooks from "eslint-plugin-react-hooks"');
|
|
2206
2591
|
}
|
|
2207
|
-
const ignoresArray = JSON.stringify(
|
|
2592
|
+
const ignoresArray = JSON.stringify(options.config.ignorePatterns);
|
|
2208
2593
|
const unusedVarsRule = isTypescript ? "@typescript-eslint/no-unused-vars" : "no-unused-vars";
|
|
2209
2594
|
const rulesConfig = {
|
|
2210
2595
|
[unusedVarsRule]: [
|
|
@@ -2238,34 +2623,30 @@ function generateEslint(generator, options) {
|
|
|
2238
2623
|
},`,
|
|
2239
2624
|
"]"
|
|
2240
2625
|
].filter(Boolean).join("\n");
|
|
2241
|
-
const isStealth =
|
|
2626
|
+
const isStealth = builder.isStealthConfig();
|
|
2242
2627
|
if (isStealth) {
|
|
2243
|
-
|
|
2628
|
+
builder.addFile(".config/eslint.config.js", {
|
|
2244
2629
|
type: "text",
|
|
2245
2630
|
content: configContent
|
|
2246
2631
|
});
|
|
2247
|
-
|
|
2248
|
-
generator.addVscodeSetting("eslint.options", {
|
|
2249
|
-
overrideConfigFile: ".config/eslint.config.js"
|
|
2250
|
-
});
|
|
2632
|
+
builder.addScripts(packageJsonScripts.lint.eslint(".config/eslint.config.js"));
|
|
2251
2633
|
} else {
|
|
2252
|
-
|
|
2634
|
+
builder.addFile("eslint.config.js", {
|
|
2253
2635
|
type: "text",
|
|
2254
2636
|
content: configContent
|
|
2255
2637
|
});
|
|
2256
|
-
|
|
2638
|
+
builder.addScripts(packageJsonScripts.lint.eslint());
|
|
2257
2639
|
}
|
|
2258
|
-
|
|
2640
|
+
builder.inject(
|
|
2259
2641
|
"readme-tools",
|
|
2260
2642
|
"[ESLint](https://eslint.org/) - Linter for JavaScript and TypeScript"
|
|
2261
2643
|
);
|
|
2262
|
-
|
|
2263
|
-
generator.addVscodeSetting("eslint.enable", true);
|
|
2644
|
+
builder.inject("vscode-extension-suggestion", "dbaeumer.vscode-eslint");
|
|
2264
2645
|
}
|
|
2265
2646
|
|
|
2266
|
-
function
|
|
2267
|
-
|
|
2268
|
-
|
|
2647
|
+
function planFiber(builder, _options) {
|
|
2648
|
+
builder.inject("import", `import { Box } from "./box.js"`);
|
|
2649
|
+
builder.inject(
|
|
2269
2650
|
"scene",
|
|
2270
2651
|
[
|
|
2271
2652
|
`<ambientLight intensity={Math.PI / 2} />`,
|
|
@@ -2275,7 +2656,7 @@ function generateFiber(generator, _options) {
|
|
|
2275
2656
|
`<Box position={[1.2, 0, 0]} />`
|
|
2276
2657
|
].join("\n")
|
|
2277
2658
|
);
|
|
2278
|
-
|
|
2659
|
+
builder.addFile("src/box.tsx", {
|
|
2279
2660
|
type: "text",
|
|
2280
2661
|
content: `import type { Mesh } from 'three'
|
|
2281
2662
|
import { useRef, useState } from 'react'
|
|
@@ -2302,11 +2683,11 @@ export function Box(props: ThreeElements['mesh']) {
|
|
|
2302
2683
|
});
|
|
2303
2684
|
}
|
|
2304
2685
|
|
|
2305
|
-
function
|
|
2306
|
-
if (options === false || getPackageManagerName(
|
|
2686
|
+
function planGithubPages(builder, options) {
|
|
2687
|
+
if (options === false || getPackageManagerName(builder.options.packageManager) !== "npm") {
|
|
2307
2688
|
return;
|
|
2308
2689
|
}
|
|
2309
|
-
|
|
2690
|
+
builder.addFile(".github/workflows/gh-pages.yml", {
|
|
2310
2691
|
type: "text",
|
|
2311
2692
|
content: `name: Deploy to Github Pages
|
|
2312
2693
|
|
|
@@ -2352,10 +2733,10 @@ jobs:
|
|
|
2352
2733
|
uses: actions/deploy-pages@v4
|
|
2353
2734
|
`
|
|
2354
2735
|
});
|
|
2355
|
-
|
|
2356
|
-
if (
|
|
2357
|
-
const address = `${
|
|
2358
|
-
|
|
2736
|
+
builder.inject("readme-start", `A github pages deployment action is configurd.`);
|
|
2737
|
+
if (builder.options.githubUserName != null && builder.options.githubRepoName != null) {
|
|
2738
|
+
const address = `${builder.options.githubUserName}.github.io/${builder.options.githubRepoName}`;
|
|
2739
|
+
builder.inject(
|
|
2359
2740
|
"readme-start",
|
|
2360
2741
|
`Your app will be publish at [${address}](https://${address}) once the github action is finished.
|
|
2361
2742
|
`
|
|
@@ -2363,228 +2744,199 @@ jobs:
|
|
|
2363
2744
|
}
|
|
2364
2745
|
}
|
|
2365
2746
|
|
|
2366
|
-
function
|
|
2747
|
+
function planHandle(builder, options) {
|
|
2367
2748
|
if (options == null) {
|
|
2368
2749
|
return;
|
|
2369
2750
|
}
|
|
2370
|
-
|
|
2371
|
-
|
|
2751
|
+
builder.addDependency("@react-three/handle");
|
|
2752
|
+
builder.inject(
|
|
2372
2753
|
"readme-libraries",
|
|
2373
2754
|
`[@react-three/handle](https://pmndrs.github.io/xr/docs/handles/introduction) - interactive controls and handles for your 3D objects`
|
|
2374
2755
|
);
|
|
2375
2756
|
}
|
|
2376
2757
|
|
|
2377
|
-
function
|
|
2758
|
+
function planKoota(builder, options) {
|
|
2378
2759
|
if (options == null) {
|
|
2379
2760
|
return;
|
|
2380
2761
|
}
|
|
2381
|
-
|
|
2382
|
-
|
|
2762
|
+
builder.addDependency("koota");
|
|
2763
|
+
builder.inject(
|
|
2383
2764
|
"readme-libraries",
|
|
2384
2765
|
`[koota](https://github.com/pmndrs/koota) - ECS-based state management library optimized for real-time apps, games, and XR experiences`
|
|
2385
2766
|
);
|
|
2386
2767
|
}
|
|
2387
2768
|
|
|
2388
|
-
function
|
|
2769
|
+
function planLeva(builder, options) {
|
|
2389
2770
|
if (options == null) {
|
|
2390
2771
|
return;
|
|
2391
2772
|
}
|
|
2392
|
-
|
|
2393
|
-
|
|
2773
|
+
builder.addDependency("leva");
|
|
2774
|
+
builder.inject(
|
|
2394
2775
|
"readme-libraries",
|
|
2395
2776
|
`[leva](https://github.com/pmndrs/leva) - HTML GUI panel for React with lightweight, beautiful and extensible controls`
|
|
2396
2777
|
);
|
|
2397
2778
|
}
|
|
2398
2779
|
|
|
2399
|
-
function
|
|
2780
|
+
function planOffscreen(builder, options) {
|
|
2400
2781
|
if (options == null) {
|
|
2401
2782
|
return;
|
|
2402
2783
|
}
|
|
2403
|
-
if (
|
|
2784
|
+
if (builder.options.xr != null) {
|
|
2404
2785
|
console.info(
|
|
2405
2786
|
color__default.blue("Info:"),
|
|
2406
2787
|
"@react-three/offscreen is disabled because it is not supported with XR"
|
|
2407
2788
|
);
|
|
2408
2789
|
return;
|
|
2409
2790
|
}
|
|
2410
|
-
|
|
2411
|
-
|
|
2791
|
+
builder.addDependency("@react-three/offscreen");
|
|
2792
|
+
builder.inject(
|
|
2412
2793
|
"readme-libraries",
|
|
2413
2794
|
`[@react-three/offscreen](https://github.com/pmndrs/offscreen) - Offload your scene to a worker thread for better performance`
|
|
2414
2795
|
);
|
|
2415
2796
|
}
|
|
2416
2797
|
|
|
2417
|
-
function
|
|
2418
|
-
|
|
2798
|
+
function planOxfmt(builder, options) {
|
|
2799
|
+
if (options == null) {
|
|
2800
|
+
return;
|
|
2801
|
+
}
|
|
2802
|
+
const isMonorepo = builder.options.workspaceRoot != null;
|
|
2419
2803
|
if (isMonorepo) {
|
|
2420
|
-
|
|
2804
|
+
builder.addDevDependency("@config/oxfmt", { version: "workspace:*" });
|
|
2421
2805
|
const configPath = "node_modules/@config/oxfmt/base.json";
|
|
2422
|
-
|
|
2423
|
-
generator.addVscodeSetting("oxc.fmt.configPath", configPath);
|
|
2806
|
+
builder.addScripts(packageJsonScripts.format.oxfmt(configPath));
|
|
2424
2807
|
} else {
|
|
2425
|
-
|
|
2426
|
-
const isStealth =
|
|
2808
|
+
builder.addDevDependency("oxfmt");
|
|
2809
|
+
const isStealth = builder.isStealthConfig();
|
|
2427
2810
|
if (isStealth) {
|
|
2428
|
-
|
|
2811
|
+
builder.addFile(".config/oxfmt.json", {
|
|
2429
2812
|
type: "text",
|
|
2430
|
-
content: JSON.stringify(
|
|
2813
|
+
content: JSON.stringify(toOxfmtConfig(options.config), null, 2)
|
|
2431
2814
|
});
|
|
2432
|
-
|
|
2433
|
-
generator.addVscodeSetting("oxc.fmt.configPath", ".config/oxfmt.json");
|
|
2815
|
+
builder.addScripts(packageJsonScripts.format.oxfmt(".config/oxfmt.json"));
|
|
2434
2816
|
} else {
|
|
2435
|
-
|
|
2817
|
+
builder.addFile("oxfmt.json", {
|
|
2436
2818
|
type: "text",
|
|
2437
|
-
content: JSON.stringify(
|
|
2819
|
+
content: JSON.stringify(toOxfmtConfig(options.config), null, 2)
|
|
2438
2820
|
});
|
|
2439
|
-
|
|
2821
|
+
builder.addScripts(packageJsonScripts.format.oxfmt("oxfmt.json"));
|
|
2440
2822
|
}
|
|
2441
2823
|
}
|
|
2442
|
-
|
|
2824
|
+
builder.inject(
|
|
2443
2825
|
"readme-tools",
|
|
2444
2826
|
"[Oxfmt](https://oxc.rs/docs/guide/usage/formatter) - Fast Prettier-compatible code formatter"
|
|
2445
2827
|
);
|
|
2446
|
-
|
|
2447
|
-
generator.addVscodeSetting("editor.defaultFormatter", "oxc.oxc-vscode");
|
|
2448
|
-
generator.addVscodeSetting("[json]", {
|
|
2449
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
2450
|
-
});
|
|
2451
|
-
generator.addVscodeSetting("[jsonc]", {
|
|
2452
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
2453
|
-
});
|
|
2454
|
-
generator.addVscodeSetting("[markdown]", {
|
|
2455
|
-
"editor.defaultFormatter": "vscode.markdown-language-features"
|
|
2456
|
-
});
|
|
2457
|
-
generator.addVscodeSetting("[yaml]", {
|
|
2458
|
-
"editor.defaultFormatter": "redhat.vscode-yaml"
|
|
2459
|
-
});
|
|
2828
|
+
builder.inject("vscode-extension-suggestion", "oxc.oxc-vscode");
|
|
2460
2829
|
}
|
|
2461
2830
|
|
|
2462
|
-
function
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
const template =
|
|
2831
|
+
function planOxlint(builder, options) {
|
|
2832
|
+
if (options == null) {
|
|
2833
|
+
return;
|
|
2834
|
+
}
|
|
2835
|
+
const template = builder.options.template ?? "vanilla";
|
|
2467
2836
|
const baseTemplate = getBaseTemplate(template);
|
|
2837
|
+
const isTypescript = getLanguageFromTemplate(template) === "typescript";
|
|
2468
2838
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2469
|
-
const isMonorepo =
|
|
2839
|
+
const isMonorepo = builder.options.workspaceRoot != null;
|
|
2470
2840
|
if (isMonorepo) {
|
|
2471
|
-
|
|
2841
|
+
builder.addDevDependency("@config/oxlint", { version: "workspace:*" });
|
|
2472
2842
|
const configPath = isReact ? "node_modules/@config/oxlint/react.json" : "node_modules/@config/oxlint/base.json";
|
|
2473
|
-
|
|
2474
|
-
generator.addVscodeSetting("oxc.configPath", configPath);
|
|
2843
|
+
builder.addScripts(packageJsonScripts.lint.oxlint(configPath));
|
|
2475
2844
|
} else {
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
"no-unused-vars": [
|
|
2488
|
-
toOxlintLevel(rules.noUnusedVars.level),
|
|
2489
|
-
{
|
|
2490
|
-
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
2491
|
-
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
2492
|
-
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
2493
|
-
}
|
|
2494
|
-
],
|
|
2495
|
-
"no-useless-escape": "off",
|
|
2496
|
-
"no-unused-expressions": [
|
|
2497
|
-
toOxlintLevel(rules.noUnusedExpressions.level),
|
|
2498
|
-
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
2499
|
-
]
|
|
2500
|
-
},
|
|
2501
|
-
ignorePatterns: defaultLinterConfig.ignorePatterns
|
|
2502
|
-
};
|
|
2845
|
+
builder.addDevDependency("oxlint");
|
|
2846
|
+
if (isTypescript) {
|
|
2847
|
+
builder.addDevDependency("oxlint-tsgolint");
|
|
2848
|
+
}
|
|
2849
|
+
const isStealth = builder.isStealthConfig();
|
|
2850
|
+
const oxlintConfig = renderOxlintConfig({
|
|
2851
|
+
schemaPath: isStealth ? "../node_modules/oxlint/configuration_schema.json" : "./node_modules/oxlint/configuration_schema.json",
|
|
2852
|
+
react: isReact,
|
|
2853
|
+
typescript: isTypescript,
|
|
2854
|
+
config: options.config
|
|
2855
|
+
});
|
|
2503
2856
|
if (isStealth) {
|
|
2504
|
-
|
|
2857
|
+
builder.addFile(".config/oxlint.json", {
|
|
2505
2858
|
type: "text",
|
|
2506
2859
|
content: JSON.stringify(oxlintConfig, null, 2)
|
|
2507
2860
|
});
|
|
2508
|
-
|
|
2509
|
-
generator.addVscodeSetting("oxc.configPath", ".config/oxlint.json");
|
|
2861
|
+
builder.addScripts(packageJsonScripts.lint.oxlint(".config/oxlint.json"));
|
|
2510
2862
|
} else {
|
|
2511
|
-
|
|
2863
|
+
builder.addFile("oxlint.json", {
|
|
2512
2864
|
type: "text",
|
|
2513
2865
|
content: JSON.stringify(oxlintConfig, null, 2)
|
|
2514
2866
|
});
|
|
2515
|
-
|
|
2867
|
+
builder.addScripts(packageJsonScripts.lint.oxlint());
|
|
2516
2868
|
}
|
|
2517
2869
|
}
|
|
2518
|
-
|
|
2870
|
+
builder.inject(
|
|
2519
2871
|
"readme-tools",
|
|
2520
2872
|
"[Oxlint](https://oxc.rs/docs/guide/usage/linter) - A fast linter for JavaScript and TypeScript"
|
|
2521
2873
|
);
|
|
2522
|
-
|
|
2523
|
-
generator.addVscodeSetting("oxc.enable", true);
|
|
2874
|
+
builder.inject("vscode-extension-suggestion", "oxc.oxc-vscode");
|
|
2524
2875
|
}
|
|
2525
2876
|
|
|
2526
|
-
function
|
|
2877
|
+
function planPostprocessing(builder, options) {
|
|
2527
2878
|
if (options == null) {
|
|
2528
2879
|
return;
|
|
2529
2880
|
}
|
|
2530
|
-
if (
|
|
2881
|
+
if (builder.options.xr != null) {
|
|
2531
2882
|
console.info(
|
|
2532
2883
|
color__default.blue("Info:"),
|
|
2533
2884
|
"@react-three/postprocessing is disabled because it is not supported with XR"
|
|
2534
2885
|
);
|
|
2535
2886
|
return;
|
|
2536
2887
|
}
|
|
2537
|
-
|
|
2538
|
-
|
|
2888
|
+
builder.addDependency("@react-three/postprocessing");
|
|
2889
|
+
builder.inject(
|
|
2539
2890
|
"readme-libraries",
|
|
2540
2891
|
`[@react-three/postprocessing](https://react-postprocessing.docs.pmnd.rs/) - Post-processing effects for @react-three/fiber`
|
|
2541
2892
|
);
|
|
2542
2893
|
}
|
|
2543
2894
|
|
|
2544
|
-
function
|
|
2545
|
-
|
|
2546
|
-
|
|
2895
|
+
function planPrettier(builder, options) {
|
|
2896
|
+
if (options == null) {
|
|
2897
|
+
return;
|
|
2898
|
+
}
|
|
2899
|
+
builder.addDevDependency("prettier");
|
|
2900
|
+
const isStealth = builder.isStealthConfig();
|
|
2547
2901
|
if (isStealth) {
|
|
2548
|
-
|
|
2902
|
+
builder.addFile(".config/prettier.json", {
|
|
2903
|
+
type: "text",
|
|
2904
|
+
content: JSON.stringify(toPrettierConfig(options.config), null, 2)
|
|
2905
|
+
});
|
|
2906
|
+
builder.addFile(".config/prettierignore", {
|
|
2549
2907
|
type: "text",
|
|
2550
|
-
content:
|
|
2908
|
+
content: toPrettierIgnoreContent(options.config)
|
|
2551
2909
|
});
|
|
2552
|
-
|
|
2553
|
-
|
|
2910
|
+
builder.addScripts(
|
|
2911
|
+
packageJsonScripts.format.prettier(".config/prettier.json", ".config/prettierignore")
|
|
2912
|
+
);
|
|
2554
2913
|
} else {
|
|
2555
|
-
|
|
2914
|
+
builder.addFile(".prettierrc", {
|
|
2915
|
+
type: "text",
|
|
2916
|
+
content: JSON.stringify(toPrettierConfig(options.config), null, 2)
|
|
2917
|
+
});
|
|
2918
|
+
builder.addFile(".prettierignore", {
|
|
2556
2919
|
type: "text",
|
|
2557
|
-
content:
|
|
2920
|
+
content: toPrettierIgnoreContent(options.config)
|
|
2558
2921
|
});
|
|
2559
|
-
|
|
2922
|
+
builder.addScripts(packageJsonScripts.format.prettier());
|
|
2560
2923
|
}
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
generator.addVscodeSetting("editor.defaultFormatter", "esbenp.prettier-vscode");
|
|
2924
|
+
builder.inject("readme-tools", "[Prettier](https://prettier.io/) - Opinionated code formatter");
|
|
2925
|
+
builder.inject("vscode-extension-suggestion", "esbenp.prettier-vscode");
|
|
2564
2926
|
}
|
|
2565
2927
|
|
|
2566
|
-
function
|
|
2928
|
+
function planRapier(builder, options) {
|
|
2567
2929
|
if (options == null) {
|
|
2568
2930
|
return;
|
|
2569
2931
|
}
|
|
2570
|
-
|
|
2571
|
-
|
|
2932
|
+
builder.addDependency("@react-three/rapier");
|
|
2933
|
+
builder.inject(
|
|
2572
2934
|
"readme-libraries",
|
|
2573
2935
|
`[@react-three/rapier](https://github.com/pmndrs/react-three-rapier) - Physics based on Rapier for your @react-three/fiber scene`
|
|
2574
2936
|
);
|
|
2575
2937
|
}
|
|
2576
2938
|
|
|
2577
|
-
function
|
|
2578
|
-
const set = /* @__PURE__ */ new Set();
|
|
2579
|
-
for (const arr of array) {
|
|
2580
|
-
for (const item of arr) {
|
|
2581
|
-
set.add(item);
|
|
2582
|
-
}
|
|
2583
|
-
}
|
|
2584
|
-
return Array.from(set);
|
|
2585
|
-
}
|
|
2586
|
-
|
|
2587
|
-
function generateProvidersModule(generator) {
|
|
2939
|
+
function generateProvidersModule(builder) {
|
|
2588
2940
|
const canvasProviders = [];
|
|
2589
2941
|
const globalProviders = [];
|
|
2590
2942
|
const providerDefs = {
|
|
@@ -2650,29 +3002,23 @@ function generateProvidersModule(generator) {
|
|
|
2650
3002
|
]
|
|
2651
3003
|
}
|
|
2652
3004
|
};
|
|
2653
|
-
if (
|
|
3005
|
+
if (builder.options.rapier) {
|
|
2654
3006
|
canvasProviders.push("rapier");
|
|
2655
3007
|
}
|
|
2656
|
-
if (!!
|
|
3008
|
+
if (!!builder.options.postprocessing && !builder.options.xr) {
|
|
2657
3009
|
canvasProviders.push("postprocessing");
|
|
2658
3010
|
}
|
|
2659
|
-
if (
|
|
3011
|
+
if (builder.options.uikit) {
|
|
2660
3012
|
globalProviders.push("uikit");
|
|
2661
3013
|
}
|
|
2662
3014
|
function generateProviderFunction(name, { jsdoc, providers }) {
|
|
2663
3015
|
const resolvedProviders = providers.map((provider) => providerDefs[provider]);
|
|
2664
3016
|
const providerProps = resolvedProviders.flatMap((provider) => provider.props || []);
|
|
2665
3017
|
const providerImports = resolvedProviders.flatMap((provider) => provider.import);
|
|
2666
|
-
const wrappedComponents = resolvedProviders.filter(
|
|
2667
|
-
|
|
2668
|
-
);
|
|
2669
|
-
const
|
|
2670
|
-
(provider) => provider.type === "inline-jsx"
|
|
2671
|
-
);
|
|
2672
|
-
const layoutEffects = resolvedProviders.filter(
|
|
2673
|
-
(provider) => provider.type === "layout-effect"
|
|
2674
|
-
);
|
|
2675
|
-
const declaredProps = providerProps.map((prop) => `${prop.declaredPropName} = ${prop.declaredPropDefaultValue}`).join(", ");
|
|
3018
|
+
const wrappedComponents = resolvedProviders.filter((provider) => provider.type === "wrapped-jsx");
|
|
3019
|
+
const inlineComponents = resolvedProviders.filter((provider) => provider.type === "inline-jsx");
|
|
3020
|
+
const layoutEffects = resolvedProviders.filter((provider) => provider.type === "layout-effect");
|
|
3021
|
+
const declaredProps = providerProps.map((prop) => `${prop.declaredPropName} = ${String(prop.declaredPropDefaultValue)}`).join(", ");
|
|
2676
3022
|
const declaredTypes = providerProps.map((prop) => `${prop.declaredPropName}?: ${prop.declaredPropType}`).join("; ");
|
|
2677
3023
|
const reactImports = ["type ReactNode"];
|
|
2678
3024
|
if (layoutEffects.length) {
|
|
@@ -2689,11 +3035,11 @@ ${jsdoc.split("\n").map((line) => ` * ${line}`).join("\n")}
|
|
|
2689
3035
|
${layoutEffects.length ? `
|
|
2690
3036
|
useLayoutEffect(() => {
|
|
2691
3037
|
${layoutEffects.map((effect) => effect.code).join("\n")}
|
|
2692
|
-
}, [${layoutEffects.map((effect) => effect.props?.[0]?.propValue)}]);
|
|
3038
|
+
}, [${layoutEffects.map((effect) => effect.props?.[0]?.propValue).join(", ")}]);
|
|
2693
3039
|
` : ""}
|
|
2694
3040
|
return (
|
|
2695
3041
|
<>
|
|
2696
|
-
${inlineComponents.map((provider) => provider.code)}
|
|
3042
|
+
${inlineComponents.map((provider) => provider.code).join("\n")}
|
|
2697
3043
|
${wrappedComponents.reduce((acc, provider) => {
|
|
2698
3044
|
const props = provider.props?.map((prop) => `${prop.propName}={${prop.propValue}}`).join(" ");
|
|
2699
3045
|
return `<${provider.component} ${props}>${acc}</${provider.component}>`;
|
|
@@ -2719,20 +3065,20 @@ ${jsdoc.split("\n").map((line) => ` * ${line}`).join("\n")}
|
|
|
2719
3065
|
${canvas.code}
|
|
2720
3066
|
`;
|
|
2721
3067
|
}
|
|
2722
|
-
function
|
|
3068
|
+
function planTriplex(builder, options) {
|
|
2723
3069
|
if (options == null) {
|
|
2724
3070
|
return;
|
|
2725
3071
|
}
|
|
2726
|
-
|
|
2727
|
-
|
|
3072
|
+
builder.inject("vscode-extension-suggestion", "trytriplex.triplex-vsce");
|
|
3073
|
+
builder.inject(
|
|
2728
3074
|
"readme-tools",
|
|
2729
3075
|
`[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).`
|
|
2730
3076
|
);
|
|
2731
|
-
|
|
2732
|
-
content: generateProvidersModule(
|
|
3077
|
+
builder.addFile(".triplex/providers.tsx", {
|
|
3078
|
+
content: generateProvidersModule(builder),
|
|
2733
3079
|
type: "text"
|
|
2734
3080
|
});
|
|
2735
|
-
|
|
3081
|
+
builder.addFile(".triplex/config.json", {
|
|
2736
3082
|
content: JSON.stringify(
|
|
2737
3083
|
{
|
|
2738
3084
|
$schema: "https://triplex.dev/config.schema.json",
|
|
@@ -2745,9 +3091,9 @@ function generateTriplex(generator, options) {
|
|
|
2745
3091
|
});
|
|
2746
3092
|
}
|
|
2747
3093
|
|
|
2748
|
-
function
|
|
2749
|
-
|
|
2750
|
-
const template =
|
|
3094
|
+
function planTsdown(builder) {
|
|
3095
|
+
builder.addDevDependency("tsdown");
|
|
3096
|
+
const template = builder.options.template ?? "vanilla";
|
|
2751
3097
|
const baseTemplate = getBaseTemplate(template);
|
|
2752
3098
|
const language = getLanguageFromTemplate(template);
|
|
2753
3099
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
@@ -2767,36 +3113,36 @@ function generateTsdown(generator) {
|
|
|
2767
3113
|
configLines.push(` },`);
|
|
2768
3114
|
}
|
|
2769
3115
|
configLines.push(`})`);
|
|
2770
|
-
|
|
3116
|
+
builder.addFile(`tsdown.config.${ext}`, {
|
|
2771
3117
|
type: "text",
|
|
2772
3118
|
content: configLines.join("\n")
|
|
2773
3119
|
});
|
|
2774
|
-
|
|
2775
|
-
|
|
3120
|
+
builder.addScripts(packageJsonScripts.build.tsdown);
|
|
3121
|
+
builder.inject(
|
|
2776
3122
|
"readme-libraries",
|
|
2777
3123
|
"[tsdown](https://github.com/nicepkg/tsdown) - Fast TypeScript bundler powered by esbuild"
|
|
2778
3124
|
);
|
|
2779
3125
|
}
|
|
2780
3126
|
|
|
2781
|
-
function
|
|
3127
|
+
function planUikit(builder, options) {
|
|
2782
3128
|
if (options == null) {
|
|
2783
3129
|
return;
|
|
2784
3130
|
}
|
|
2785
|
-
|
|
2786
|
-
|
|
3131
|
+
builder.addDependency("@react-three/uikit");
|
|
3132
|
+
builder.inject(
|
|
2787
3133
|
"readme-libraries",
|
|
2788
3134
|
`[@react-three/uikit](https://pmndrs.github.io/uikit/docs/) - UI primitives for React Three Fiber`
|
|
2789
3135
|
);
|
|
2790
3136
|
}
|
|
2791
3137
|
|
|
2792
|
-
function
|
|
2793
|
-
|
|
2794
|
-
const template =
|
|
3138
|
+
function planUnbuild(builder) {
|
|
3139
|
+
builder.addDevDependency("unbuild");
|
|
3140
|
+
const template = builder.options.template ?? "vanilla";
|
|
2795
3141
|
const baseTemplate = getBaseTemplate(template);
|
|
2796
3142
|
const language = getLanguageFromTemplate(template);
|
|
2797
3143
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2798
3144
|
const ext = language === "typescript" ? "ts" : "js";
|
|
2799
|
-
const isMonorepo =
|
|
3145
|
+
const isMonorepo = builder.options.workspaceRoot != null;
|
|
2800
3146
|
const buildConfigLines = [
|
|
2801
3147
|
`import { defineBuildConfig } from "unbuild"`,
|
|
2802
3148
|
``,
|
|
@@ -2814,51 +3160,54 @@ function generateUnbuild(generator) {
|
|
|
2814
3160
|
}
|
|
2815
3161
|
buildConfigLines.push(` },`);
|
|
2816
3162
|
buildConfigLines.push(`})`);
|
|
2817
|
-
const isStealth =
|
|
3163
|
+
const isStealth = builder.isStealthConfig() && !isMonorepo;
|
|
2818
3164
|
if (isStealth) {
|
|
2819
|
-
|
|
3165
|
+
builder.addFile(`.config/build.config.${ext}`, {
|
|
2820
3166
|
type: "text",
|
|
2821
3167
|
content: buildConfigLines.join("\n")
|
|
2822
3168
|
});
|
|
2823
|
-
|
|
3169
|
+
builder.addScripts(packageJsonScripts.build.unbuild(`.config/build.config.${ext}`));
|
|
2824
3170
|
} else {
|
|
2825
|
-
|
|
3171
|
+
builder.addFile(`build.config.${ext}`, {
|
|
2826
3172
|
type: "text",
|
|
2827
3173
|
content: buildConfigLines.join("\n")
|
|
2828
3174
|
});
|
|
2829
|
-
|
|
3175
|
+
builder.addScripts(packageJsonScripts.build.unbuild());
|
|
2830
3176
|
}
|
|
2831
|
-
|
|
3177
|
+
builder.inject(
|
|
2832
3178
|
"readme-libraries",
|
|
2833
3179
|
"[unbuild](https://github.com/unjs/unbuild) - Unified JavaScript build system"
|
|
2834
3180
|
);
|
|
2835
3181
|
}
|
|
2836
3182
|
|
|
2837
|
-
function
|
|
2838
|
-
|
|
2839
|
-
|
|
3183
|
+
function planVitest(builder, options) {
|
|
3184
|
+
if (options == null) {
|
|
3185
|
+
return;
|
|
3186
|
+
}
|
|
3187
|
+
builder.addDevDependency("vitest");
|
|
3188
|
+
const template = builder.options.template ?? "vanilla";
|
|
2840
3189
|
const baseTemplate = getBaseTemplate(template);
|
|
2841
3190
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2842
3191
|
if (isReact) {
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
3192
|
+
builder.addDevDependency("@testing-library/react");
|
|
3193
|
+
builder.addDevDependency("@testing-library/dom");
|
|
3194
|
+
builder.addDevDependency("jsdom");
|
|
2846
3195
|
}
|
|
2847
3196
|
if (isReact) {
|
|
2848
|
-
|
|
3197
|
+
builder.configureVite({ test: { environment: "jsdom" } });
|
|
2849
3198
|
}
|
|
2850
|
-
|
|
2851
|
-
|
|
3199
|
+
builder.addScripts(packageJsonScripts.test.vitest);
|
|
3200
|
+
builder.inject(
|
|
2852
3201
|
"readme-tools",
|
|
2853
3202
|
"[Vitest](https://vitest.dev/) - Fast unit test framework powered by Vite"
|
|
2854
3203
|
);
|
|
2855
3204
|
}
|
|
2856
3205
|
|
|
2857
|
-
function
|
|
2858
|
-
if (options == null || getPackageManagerName(
|
|
3206
|
+
function planViverse(builder, options) {
|
|
3207
|
+
if (options == null || getPackageManagerName(builder.options.packageManager) !== "npm") {
|
|
2859
3208
|
return;
|
|
2860
3209
|
}
|
|
2861
|
-
|
|
3210
|
+
builder.addFile(".github/workflows/viverse.yml", {
|
|
2862
3211
|
type: "text",
|
|
2863
3212
|
content: `name: Deploy to Viverse
|
|
2864
3213
|
|
|
@@ -2909,12 +3258,12 @@ jobs:
|
|
|
2909
3258
|
run: npx viverse-cli auth login -e \${{ secrets.VIVERSE_EMAIL }} -p \${{ secrets.VIVERSE_PASSWORD }}
|
|
2910
3259
|
|
|
2911
3260
|
- name: Deploy to Viverse
|
|
2912
|
-
run: npx viverse-cli app publish ./dist --auto-create-app --name ${
|
|
3261
|
+
run: npx viverse-cli app publish ./dist --auto-create-app --name ${builder.options.name}
|
|
2913
3262
|
|
|
2914
3263
|
`
|
|
2915
3264
|
});
|
|
2916
|
-
|
|
2917
|
-
|
|
3265
|
+
builder.addDependency("@viverse/cli");
|
|
3266
|
+
builder.inject(
|
|
2918
3267
|
"readme-start",
|
|
2919
3268
|
`A GitHub CI/CD workflow for publishing to Viverse is configured.
|
|
2920
3269
|
|
|
@@ -2927,36 +3276,36 @@ You can also upload your project manually using the Viverse CLI:
|
|
|
2927
3276
|
\`\`\`bash
|
|
2928
3277
|
viverse-cli auth login -e <email> -p <password>
|
|
2929
3278
|
npm run build
|
|
2930
|
-
viverse-cli app publish ./dist --auto-create-app --name ${
|
|
3279
|
+
viverse-cli app publish ./dist --auto-create-app --name ${builder.options.name}
|
|
2931
3280
|
\`\`\`
|
|
2932
3281
|
`
|
|
2933
3282
|
);
|
|
2934
3283
|
}
|
|
2935
3284
|
|
|
2936
|
-
function
|
|
3285
|
+
function planXr(builder, options) {
|
|
2937
3286
|
if (options == null || options === false) {
|
|
2938
3287
|
return;
|
|
2939
3288
|
}
|
|
2940
3289
|
if (options === true) {
|
|
2941
3290
|
options = {};
|
|
2942
3291
|
}
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
3292
|
+
builder.addDependency("@react-three/xr");
|
|
3293
|
+
builder.addDependency("@vitejs/plugin-basic-ssl");
|
|
3294
|
+
builder.inject("import", "import { XR, createXRStore } from '@react-three/xr'");
|
|
3295
|
+
builder.inject(
|
|
2947
3296
|
`global-start`,
|
|
2948
3297
|
`const store = createXRStore(${JSON.stringify(options.storeOptions ?? {})})`
|
|
2949
3298
|
);
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
3299
|
+
builder.inject("scene-start", "<XR store={store}>");
|
|
3300
|
+
builder.inject("scene-end", "</XR>");
|
|
3301
|
+
builder.inject("vite-config-import", "import basicSsl from '@vitejs/plugin-basic-ssl';");
|
|
3302
|
+
builder.configureVite({
|
|
2954
3303
|
server: {
|
|
2955
3304
|
host: true
|
|
2956
3305
|
},
|
|
2957
3306
|
plugins: ["$raw:basicSsl()"]
|
|
2958
3307
|
});
|
|
2959
|
-
|
|
3308
|
+
builder.inject(
|
|
2960
3309
|
"dom-start",
|
|
2961
3310
|
`<div style={{
|
|
2962
3311
|
display: "flex",
|
|
@@ -2988,55 +3337,226 @@ function generateXr(generator, options) {
|
|
|
2988
3337
|
Enter VR
|
|
2989
3338
|
</button></div>`
|
|
2990
3339
|
);
|
|
2991
|
-
|
|
3340
|
+
builder.inject(
|
|
2992
3341
|
"readme-libraries",
|
|
2993
3342
|
`[@react-three/xr](https://pmndrs.github.io/xr/docs/) - VR/AR support for @react-three/fiber`
|
|
2994
3343
|
);
|
|
2995
3344
|
}
|
|
2996
3345
|
|
|
2997
|
-
function
|
|
3346
|
+
function planZustand(builder, options) {
|
|
2998
3347
|
if (options == null) {
|
|
2999
3348
|
return;
|
|
3000
3349
|
}
|
|
3001
|
-
|
|
3002
|
-
|
|
3350
|
+
builder.addDependency("zustand");
|
|
3351
|
+
builder.inject(
|
|
3003
3352
|
"readme-libraries",
|
|
3004
3353
|
`[zustand](https://zustand.docs.pmnd.rs/) - small, fast and scalable state-management solution`
|
|
3005
3354
|
);
|
|
3006
3355
|
}
|
|
3007
3356
|
|
|
3008
|
-
function
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3357
|
+
function resolveProjectPlanInput(options) {
|
|
3358
|
+
const packageManager = options.packageManager ?? { name: "pnpm" };
|
|
3359
|
+
return {
|
|
3360
|
+
project: {
|
|
3361
|
+
githubUserName: options.githubUserName,
|
|
3362
|
+
githubRepoName: options.githubRepoName,
|
|
3363
|
+
name: options.name,
|
|
3364
|
+
projectType: options.projectType,
|
|
3365
|
+
template: options.template
|
|
3366
|
+
},
|
|
3367
|
+
aiAgents: {
|
|
3368
|
+
tool: "ai-agents",
|
|
3369
|
+
config: {
|
|
3370
|
+
platforms: options.aiPlatforms ?? []
|
|
3371
|
+
}
|
|
3372
|
+
},
|
|
3373
|
+
formatter: {
|
|
3374
|
+
tool: options.formatter ?? "prettier",
|
|
3375
|
+
config: structuredClone(defaultFormatterMetaConfig)
|
|
3376
|
+
},
|
|
3377
|
+
linter: {
|
|
3378
|
+
tool: options.linter ?? "oxlint",
|
|
3379
|
+
config: structuredClone(defaultLinterMetaConfig)
|
|
3380
|
+
},
|
|
3381
|
+
testing: {
|
|
3382
|
+
tool: options.testing ?? (options.projectType === "library" ? "vitest" : "none"),
|
|
3383
|
+
config: {}
|
|
3384
|
+
},
|
|
3385
|
+
typescript: {
|
|
3386
|
+
tool: "typescript",
|
|
3387
|
+
config: {
|
|
3388
|
+
configStrategy: options.configStrategy
|
|
3389
|
+
}
|
|
3390
|
+
},
|
|
3391
|
+
ide: {
|
|
3392
|
+
tool: options.ide ?? "vscode",
|
|
3393
|
+
config: {}
|
|
3394
|
+
},
|
|
3395
|
+
packageManager: {
|
|
3396
|
+
tool: packageManager.name,
|
|
3397
|
+
config: {
|
|
3398
|
+
version: packageManager.version,
|
|
3399
|
+
pnpmManageVersions: options.pnpmManageVersions
|
|
3400
|
+
}
|
|
3401
|
+
},
|
|
3402
|
+
libraryBundler: {
|
|
3403
|
+
tool: options.libraryBundler ?? "unbuild",
|
|
3404
|
+
config: {}
|
|
3405
|
+
},
|
|
3406
|
+
features: {
|
|
3407
|
+
fiber: options.fiber,
|
|
3408
|
+
handle: options.handle,
|
|
3409
|
+
drei: options.drei,
|
|
3410
|
+
koota: options.koota,
|
|
3411
|
+
leva: options.leva,
|
|
3412
|
+
offscreen: options.offscreen,
|
|
3413
|
+
postprocessing: options.postprocessing,
|
|
3414
|
+
rapier: options.rapier,
|
|
3415
|
+
triplex: options.triplex,
|
|
3416
|
+
viverse: options.viverse,
|
|
3417
|
+
uikit: options.uikit,
|
|
3418
|
+
xr: options.xr,
|
|
3419
|
+
zustand: options.zustand,
|
|
3420
|
+
githubPages: options.githubPages
|
|
3421
|
+
},
|
|
3422
|
+
context: {
|
|
3423
|
+
dependencies: options.dependencies,
|
|
3424
|
+
engine: options.engine,
|
|
3425
|
+
files: options.files,
|
|
3426
|
+
injections: options.injections,
|
|
3427
|
+
replacements: options.replacements,
|
|
3428
|
+
versions: options.versions,
|
|
3429
|
+
workspaceRoot: options.workspaceRoot,
|
|
3430
|
+
workspaceDependencies: options.workspaceDependencies
|
|
3028
3431
|
}
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3432
|
+
};
|
|
3433
|
+
}
|
|
3434
|
+
function projectPlanInputToOptions(input) {
|
|
3435
|
+
return {
|
|
3436
|
+
...input.project,
|
|
3437
|
+
aiPlatforms: input.aiAgents.config.platforms.length > 0 ? input.aiAgents.config.platforms : void 0,
|
|
3438
|
+
formatter: input.formatter.tool,
|
|
3439
|
+
linter: input.linter.tool,
|
|
3440
|
+
testing: input.testing.tool,
|
|
3441
|
+
configStrategy: input.typescript.config.configStrategy,
|
|
3442
|
+
ide: input.ide.tool,
|
|
3443
|
+
packageManager: packageManagerSpecFromInput(input.packageManager),
|
|
3444
|
+
pnpmManageVersions: input.packageManager.config.pnpmManageVersions,
|
|
3445
|
+
libraryBundler: input.libraryBundler.tool,
|
|
3446
|
+
...input.features,
|
|
3447
|
+
dependencies: input.context.dependencies,
|
|
3448
|
+
engine: input.context.engine,
|
|
3449
|
+
files: input.context.files,
|
|
3450
|
+
injections: input.context.injections,
|
|
3451
|
+
replacements: input.context.replacements,
|
|
3452
|
+
versions: input.context.versions,
|
|
3453
|
+
workspaceRoot: input.context.workspaceRoot,
|
|
3454
|
+
workspaceDependencies: input.context.workspaceDependencies
|
|
3455
|
+
};
|
|
3456
|
+
}
|
|
3457
|
+
function resolveWorkspacePlanInput(params) {
|
|
3458
|
+
return {
|
|
3459
|
+
project: {
|
|
3460
|
+
name: params.name
|
|
3461
|
+
},
|
|
3462
|
+
aiAgents: {
|
|
3463
|
+
tool: "ai-agents",
|
|
3464
|
+
config: {
|
|
3465
|
+
platforms: params.aiPlatforms ?? []
|
|
3466
|
+
}
|
|
3467
|
+
},
|
|
3468
|
+
formatter: {
|
|
3469
|
+
tool: params.formatter,
|
|
3470
|
+
config: structuredClone(defaultFormatterMetaConfig)
|
|
3471
|
+
},
|
|
3472
|
+
linter: {
|
|
3473
|
+
tool: params.linter,
|
|
3474
|
+
config: structuredClone(defaultLinterMetaConfig)
|
|
3475
|
+
},
|
|
3476
|
+
ide: {
|
|
3477
|
+
tool: params.ide ?? "vscode",
|
|
3478
|
+
config: {}
|
|
3479
|
+
},
|
|
3480
|
+
packageManager: {
|
|
3481
|
+
tool: params.packageManager.name,
|
|
3482
|
+
config: {
|
|
3483
|
+
version: params.packageManager.version,
|
|
3484
|
+
pnpmManageVersions: params.pnpmManageVersions
|
|
3485
|
+
}
|
|
3486
|
+
},
|
|
3487
|
+
context: {
|
|
3488
|
+
engine: params.engine,
|
|
3489
|
+
pnpmManageVersions: params.pnpmManageVersions,
|
|
3490
|
+
versions: params.versions
|
|
3032
3491
|
}
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
return
|
|
3492
|
+
};
|
|
3493
|
+
}
|
|
3494
|
+
function workspacePlanInputToMonorepoParams(input) {
|
|
3495
|
+
return {
|
|
3496
|
+
name: input.project.name,
|
|
3497
|
+
linter: input.linter.tool,
|
|
3498
|
+
formatter: input.formatter.tool,
|
|
3499
|
+
packageManager: packageManagerSpecFromInput(input.packageManager),
|
|
3500
|
+
pnpmManageVersions: input.context.pnpmManageVersions,
|
|
3501
|
+
engine: input.context.engine,
|
|
3502
|
+
versions: input.context.versions,
|
|
3503
|
+
aiPlatforms: input.aiAgents.config.platforms.length > 0 ? input.aiAgents.config.platforms : void 0,
|
|
3504
|
+
ide: input.ide.tool
|
|
3505
|
+
};
|
|
3506
|
+
}
|
|
3507
|
+
function isProjectPlanInput(input) {
|
|
3508
|
+
return "project" in input && "formatter" in input && typeof input.formatter === "object";
|
|
3509
|
+
}
|
|
3510
|
+
function isWorkspacePlanInput(input) {
|
|
3511
|
+
return "project" in input && "formatter" in input && typeof input.formatter === "object";
|
|
3512
|
+
}
|
|
3513
|
+
function packageManagerSpecFromInput(packageManager) {
|
|
3514
|
+
return {
|
|
3515
|
+
name: packageManager.tool,
|
|
3516
|
+
version: packageManager.config.version
|
|
3517
|
+
};
|
|
3518
|
+
}
|
|
3519
|
+
|
|
3520
|
+
async function resolveProjectFacts(input) {
|
|
3521
|
+
const options = projectPlanInputToOptions(input);
|
|
3522
|
+
options.packageManager = await resolvePackageManager(options);
|
|
3523
|
+
options.engine = await resolveEngine(options);
|
|
3524
|
+
options.versions = await resolveProjectPackageVersions(options);
|
|
3525
|
+
return resolveProjectPlanInput(options);
|
|
3526
|
+
}
|
|
3527
|
+
async function resolveWorkspaceFacts(input) {
|
|
3528
|
+
const params = workspacePlanInputToMonorepoParams(input);
|
|
3529
|
+
const options = {
|
|
3530
|
+
name: params.name,
|
|
3531
|
+
linter: params.linter,
|
|
3532
|
+
formatter: params.formatter,
|
|
3533
|
+
packageManager: params.packageManager,
|
|
3534
|
+
engine: params.engine,
|
|
3535
|
+
pnpmManageVersions: params.pnpmManageVersions,
|
|
3536
|
+
versions: params.versions
|
|
3537
|
+
};
|
|
3538
|
+
const packageManager = await resolvePackageManager(options);
|
|
3539
|
+
const engine = await resolveEngine(options);
|
|
3540
|
+
const versions = await resolveMonorepoRootPackageVersions({
|
|
3541
|
+
linter: params.linter,
|
|
3542
|
+
formatter: params.formatter,
|
|
3543
|
+
engine,
|
|
3544
|
+
versions: params.versions
|
|
3545
|
+
});
|
|
3546
|
+
return resolveWorkspacePlanInput({
|
|
3547
|
+
...params,
|
|
3548
|
+
packageManager,
|
|
3549
|
+
engine,
|
|
3550
|
+
versions
|
|
3551
|
+
});
|
|
3037
3552
|
}
|
|
3038
3553
|
|
|
3039
|
-
function
|
|
3554
|
+
async function planProject(input) {
|
|
3555
|
+
const planInput = isProjectPlanInput(input) ? input : resolveProjectPlanInput(input);
|
|
3556
|
+
return createProjectPlan(await resolveProjectFacts(planInput));
|
|
3557
|
+
}
|
|
3558
|
+
function createProjectPlan(planInput) {
|
|
3559
|
+
const options = projectPlanInputToOptions(planInput);
|
|
3040
3560
|
const clonedOptions = structuredClone(options);
|
|
3041
3561
|
const template = clonedOptions.template ?? "vanilla";
|
|
3042
3562
|
const baseTemplate = getBaseTemplate(template);
|
|
@@ -3045,7 +3565,8 @@ function generate(options) {
|
|
|
3045
3565
|
const isReact = baseTemplate === "react";
|
|
3046
3566
|
const isR3f = baseTemplate === "r3f";
|
|
3047
3567
|
const isLibrary = clonedOptions.projectType === "library";
|
|
3048
|
-
const libraryBundler =
|
|
3568
|
+
const libraryBundler = planInput.libraryBundler.tool;
|
|
3569
|
+
const ide = planInput.ide.tool;
|
|
3049
3570
|
const files = {
|
|
3050
3571
|
...clonedOptions.files
|
|
3051
3572
|
};
|
|
@@ -3079,7 +3600,7 @@ function generate(options) {
|
|
|
3079
3600
|
}
|
|
3080
3601
|
}
|
|
3081
3602
|
if (language === "typescript") {
|
|
3082
|
-
const tsResult =
|
|
3603
|
+
const tsResult = renderTypescriptConfig({
|
|
3083
3604
|
baseTemplate,
|
|
3084
3605
|
useConfigPackage: clonedOptions.workspaceRoot != null,
|
|
3085
3606
|
configStrategy: clonedOptions.configStrategy,
|
|
@@ -3091,12 +3612,9 @@ function generate(options) {
|
|
|
3091
3612
|
}
|
|
3092
3613
|
const codeSnippets = {};
|
|
3093
3614
|
const vscodeSettings = {};
|
|
3094
|
-
const scripts =
|
|
3095
|
-
dev: "vite",
|
|
3096
|
-
build: "vite build"
|
|
3097
|
-
};
|
|
3615
|
+
const scripts = {};
|
|
3098
3616
|
if (!isLibrary && (isReact || isR3f)) {
|
|
3099
|
-
codeSnippets["vite-config-import"] = ["import react from '@vitejs/plugin-react'"];
|
|
3617
|
+
codeSnippets["vite-config-import"] = ["import react from '@vitejs/plugin-react';"];
|
|
3100
3618
|
}
|
|
3101
3619
|
if (!isLibrary && isR3f) {
|
|
3102
3620
|
codeSnippets["import"] = [`import { Canvas } from "@react-three/fiber"`];
|
|
@@ -3113,7 +3631,7 @@ function generate(options) {
|
|
|
3113
3631
|
viteConfig.resolve = { dedupe: ["three"] };
|
|
3114
3632
|
}
|
|
3115
3633
|
const isMonorepoPackage = clonedOptions.workspaceRoot != null;
|
|
3116
|
-
const
|
|
3634
|
+
const builder = {
|
|
3117
3635
|
options: clonedOptions,
|
|
3118
3636
|
versions,
|
|
3119
3637
|
getVersion(name2) {
|
|
@@ -3143,8 +3661,11 @@ function generate(options) {
|
|
|
3143
3661
|
addFile(path, content) {
|
|
3144
3662
|
files[path] = content;
|
|
3145
3663
|
},
|
|
3664
|
+
addScripts(nextScripts) {
|
|
3665
|
+
Object.assign(scripts, nextScripts);
|
|
3666
|
+
},
|
|
3146
3667
|
addScript(name2, command) {
|
|
3147
|
-
|
|
3668
|
+
this.addScripts({ [name2]: command });
|
|
3148
3669
|
},
|
|
3149
3670
|
inject(location, code) {
|
|
3150
3671
|
let entries = codeSnippets[location];
|
|
@@ -3164,71 +3685,61 @@ function generate(options) {
|
|
|
3164
3685
|
}
|
|
3165
3686
|
};
|
|
3166
3687
|
if (isR3f) {
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3688
|
+
planDrei(builder, planInput.features.drei);
|
|
3689
|
+
planHandle(builder, planInput.features.handle);
|
|
3690
|
+
planKoota(builder, planInput.features.koota);
|
|
3691
|
+
planLeva(builder, planInput.features.leva);
|
|
3692
|
+
planOffscreen(builder, planInput.features.offscreen);
|
|
3693
|
+
planPostprocessing(builder, planInput.features.postprocessing);
|
|
3694
|
+
planRapier(builder, planInput.features.rapier);
|
|
3695
|
+
planUikit(builder, planInput.features.uikit);
|
|
3696
|
+
planXr(builder, planInput.features.xr);
|
|
3697
|
+
planZustand(builder, planInput.features.zustand);
|
|
3698
|
+
planFiber(builder, planInput.features.fiber);
|
|
3699
|
+
planTriplex(builder, planInput.features.triplex);
|
|
3700
|
+
planViverse(builder, planInput.features.viverse);
|
|
3180
3701
|
}
|
|
3181
3702
|
if (!isLibrary) {
|
|
3182
|
-
|
|
3703
|
+
planGithubPages(builder, planInput.features.githubPages);
|
|
3183
3704
|
}
|
|
3184
3705
|
if (isLibrary) {
|
|
3185
3706
|
if (libraryBundler === "unbuild") {
|
|
3186
|
-
|
|
3707
|
+
planUnbuild(builder);
|
|
3187
3708
|
} else if (libraryBundler === "tsdown") {
|
|
3188
|
-
|
|
3709
|
+
planTsdown(builder);
|
|
3189
3710
|
}
|
|
3190
|
-
const packageManager2 = getPackageManagerName(clonedOptions.packageManager);
|
|
3191
|
-
generator.addScript("release", `${packageManager2} run build && ${packageManager2} publish`);
|
|
3192
3711
|
}
|
|
3193
|
-
const testing =
|
|
3712
|
+
const testing = planInput.testing.tool;
|
|
3194
3713
|
if (testing === "vitest") {
|
|
3195
|
-
|
|
3196
|
-
}
|
|
3197
|
-
const linter =
|
|
3198
|
-
const formatter =
|
|
3199
|
-
if (linter === "eslint") {
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
} else if (linter === "
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
} else if (linter === "biome") {
|
|
3208
|
-
generateBiome(generator, {
|
|
3209
|
-
linter: true,
|
|
3210
|
-
formatter: formatter === "biome"
|
|
3714
|
+
planVitest(builder, planInput.testing);
|
|
3715
|
+
}
|
|
3716
|
+
const linter = planInput.linter.tool;
|
|
3717
|
+
const formatter = planInput.formatter.tool;
|
|
3718
|
+
if (planInput.linter.tool === "eslint") {
|
|
3719
|
+
planEslint(builder, planInput.linter);
|
|
3720
|
+
} else if (planInput.linter.tool === "oxlint") {
|
|
3721
|
+
planOxlint(builder, planInput.linter);
|
|
3722
|
+
} else if (planInput.linter.tool === "biome") {
|
|
3723
|
+
planBiome(builder, {
|
|
3724
|
+
linter: planInput.linter,
|
|
3725
|
+
formatter: planInput.formatter.tool === "biome" ? planInput.formatter : void 0
|
|
3211
3726
|
});
|
|
3212
|
-
generator.addVscodeSetting("eslint.enable", false);
|
|
3213
|
-
generator.addVscodeSetting("oxc.enable", false);
|
|
3214
3727
|
}
|
|
3215
|
-
if (formatter === "prettier") {
|
|
3216
|
-
|
|
3217
|
-
} else if (formatter === "oxfmt") {
|
|
3218
|
-
|
|
3219
|
-
} else if (formatter === "biome" && linter !== "biome") {
|
|
3220
|
-
|
|
3221
|
-
generator.addVscodeSetting("eslint.enable", false);
|
|
3222
|
-
generator.addVscodeSetting("oxc.enable", false);
|
|
3728
|
+
if (planInput.formatter.tool === "prettier") {
|
|
3729
|
+
planPrettier(builder, planInput.formatter);
|
|
3730
|
+
} else if (planInput.formatter.tool === "oxfmt") {
|
|
3731
|
+
planOxfmt(builder, planInput.formatter);
|
|
3732
|
+
} else if (planInput.formatter.tool === "biome" && planInput.linter.tool !== "biome") {
|
|
3733
|
+
planBiome(builder, { formatter: planInput.formatter });
|
|
3223
3734
|
}
|
|
3224
3735
|
for (const { code, location } of clonedOptions.injections ?? []) {
|
|
3225
|
-
|
|
3736
|
+
builder.inject(location, code);
|
|
3226
3737
|
}
|
|
3227
3738
|
if (!isLibrary) {
|
|
3228
|
-
files["vite.config.ts"] =
|
|
3739
|
+
files["vite.config.ts"] = renderViteConfig({ viteConfig, codeSnippets });
|
|
3229
3740
|
}
|
|
3230
3741
|
const packageManager = getPackageManagerName(options.packageManager);
|
|
3231
|
-
files["README.md"] =
|
|
3742
|
+
files["README.md"] = renderReadme({
|
|
3232
3743
|
name,
|
|
3233
3744
|
baseTemplate,
|
|
3234
3745
|
isLibrary,
|
|
@@ -3238,7 +3749,7 @@ function generate(options) {
|
|
|
3238
3749
|
});
|
|
3239
3750
|
Object.assign(
|
|
3240
3751
|
files,
|
|
3241
|
-
|
|
3752
|
+
renderSourceFiles({
|
|
3242
3753
|
name,
|
|
3243
3754
|
baseTemplate,
|
|
3244
3755
|
language,
|
|
@@ -3250,7 +3761,7 @@ function generate(options) {
|
|
|
3250
3761
|
if (testing === "vitest") {
|
|
3251
3762
|
Object.assign(
|
|
3252
3763
|
files,
|
|
3253
|
-
|
|
3764
|
+
renderTestFiles({
|
|
3254
3765
|
baseTemplate,
|
|
3255
3766
|
language,
|
|
3256
3767
|
isLibrary
|
|
@@ -3259,7 +3770,7 @@ function generate(options) {
|
|
|
3259
3770
|
}
|
|
3260
3771
|
Object.assign(
|
|
3261
3772
|
files,
|
|
3262
|
-
|
|
3773
|
+
renderPackageJson({
|
|
3263
3774
|
name,
|
|
3264
3775
|
language,
|
|
3265
3776
|
isLibrary,
|
|
@@ -3271,25 +3782,54 @@ function generate(options) {
|
|
|
3271
3782
|
workspaceDependencies: clonedOptions.workspaceDependencies
|
|
3272
3783
|
}).files
|
|
3273
3784
|
);
|
|
3274
|
-
if (!isMonorepoPackage) {
|
|
3275
|
-
Object.assign(
|
|
3785
|
+
if (!isMonorepoPackage && ide === "vscode") {
|
|
3786
|
+
Object.assign(
|
|
3787
|
+
files,
|
|
3788
|
+
renderVscodeFiles$1({
|
|
3789
|
+
codeSnippets,
|
|
3790
|
+
vscodeSettings,
|
|
3791
|
+
linter,
|
|
3792
|
+
formatter,
|
|
3793
|
+
configStrategy: clonedOptions.configStrategy,
|
|
3794
|
+
isMonorepo: false,
|
|
3795
|
+
packageManager
|
|
3796
|
+
})
|
|
3797
|
+
);
|
|
3276
3798
|
}
|
|
3277
3799
|
if (!isMonorepoPackage) {
|
|
3278
|
-
files[".
|
|
3279
|
-
files[".
|
|
3800
|
+
files[".editorconfig"] = renderEditorConfig();
|
|
3801
|
+
files[".gitignore"] = renderGitignore("standalone");
|
|
3802
|
+
files[".gitattributes"] = { type: "text", content: gitAttributesContent };
|
|
3280
3803
|
}
|
|
3281
|
-
if (!isMonorepoPackage &&
|
|
3282
|
-
|
|
3804
|
+
if (!isMonorepoPackage && planInput.aiAgents.config.platforms.length > 0) {
|
|
3805
|
+
renderAiFiles(files, {
|
|
3283
3806
|
name,
|
|
3284
3807
|
packageManager: getPackageManagerName(clonedOptions.packageManager),
|
|
3285
3808
|
linter: clonedOptions.linter ?? "oxlint",
|
|
3286
3809
|
formatter: clonedOptions.formatter ?? "prettier",
|
|
3287
3810
|
isMonorepo: false,
|
|
3288
3811
|
configStrategy: clonedOptions.configStrategy,
|
|
3289
|
-
|
|
3812
|
+
hasTypecheck: language === "typescript",
|
|
3813
|
+
platforms: planInput.aiAgents.config.platforms
|
|
3290
3814
|
});
|
|
3291
3815
|
}
|
|
3292
|
-
return
|
|
3816
|
+
return {
|
|
3817
|
+
files,
|
|
3818
|
+
dependencies,
|
|
3819
|
+
devDependencies,
|
|
3820
|
+
peerDependencies,
|
|
3821
|
+
scripts,
|
|
3822
|
+
vscodeSettings,
|
|
3823
|
+
vscodeExtensions: [...new Set(codeSnippets["vscode-extension-suggestion"] ?? [])],
|
|
3824
|
+
injections: Object.entries(codeSnippets).flatMap(
|
|
3825
|
+
([location, entries]) => (entries ?? []).map((code) => ({
|
|
3826
|
+
location,
|
|
3827
|
+
code
|
|
3828
|
+
}))
|
|
3829
|
+
),
|
|
3830
|
+
replacements,
|
|
3831
|
+
warnings: []
|
|
3832
|
+
};
|
|
3293
3833
|
}
|
|
3294
3834
|
function resolveDependencySemver(name, versions, options = {}) {
|
|
3295
3835
|
if (options.version != null) {
|
|
@@ -3298,22 +3838,30 @@ function resolveDependencySemver(name, versions, options = {}) {
|
|
|
3298
3838
|
return formatResolvedPackageVersion(versions, name, options.prefix);
|
|
3299
3839
|
}
|
|
3300
3840
|
|
|
3841
|
+
async function planWorkspace(input) {
|
|
3842
|
+
const planInput = isWorkspacePlanInput(input) ? input : resolveWorkspacePlanInput(input);
|
|
3843
|
+
const resolvedInput = await resolveWorkspaceFacts(planInput);
|
|
3844
|
+
const { files } = renderMonorepo(workspacePlanInputToMonorepoParams(resolvedInput));
|
|
3845
|
+
return {
|
|
3846
|
+
files,
|
|
3847
|
+
dependencies: {},
|
|
3848
|
+
devDependencies: {},
|
|
3849
|
+
peerDependencies: {},
|
|
3850
|
+
scripts: {},
|
|
3851
|
+
vscodeSettings: {},
|
|
3852
|
+
vscodeExtensions: [],
|
|
3853
|
+
injections: [],
|
|
3854
|
+
replacements: [],
|
|
3855
|
+
warnings: []
|
|
3856
|
+
};
|
|
3857
|
+
}
|
|
3858
|
+
|
|
3301
3859
|
exports.AI_PLATFORM_HINTS = AI_PLATFORM_HINTS;
|
|
3302
3860
|
exports.AI_PLATFORM_LABELS = AI_PLATFORM_LABELS;
|
|
3303
3861
|
exports.ALL_AI_PLATFORMS = ALL_AI_PLATFORMS;
|
|
3304
3862
|
exports.detectTooling = detectTooling;
|
|
3305
3863
|
exports.formatResolvedPackageVersion = formatResolvedPackageVersion;
|
|
3306
|
-
exports.generate = generate;
|
|
3307
|
-
exports.generateAiFiles = generateAiFiles;
|
|
3308
|
-
exports.generateEslintConfigPackage = generateEslintConfigPackage;
|
|
3309
|
-
exports.generateGitignore = generateGitignore;
|
|
3310
|
-
exports.generateMonorepo = generateMonorepo;
|
|
3311
|
-
exports.generateOxfmtConfigPackage = generateOxfmtConfigPackage;
|
|
3312
|
-
exports.generateOxlintConfigPackage = generateOxlintConfigPackage;
|
|
3313
|
-
exports.generatePrettierConfigPackage = generatePrettierConfigPackage;
|
|
3314
3864
|
exports.generateRandomName = generateRandomName;
|
|
3315
|
-
exports.generateTypescriptConfigPackage = generateTypescriptConfigPackage;
|
|
3316
|
-
exports.generateVscodeFiles = generateVscodeFiles;
|
|
3317
3865
|
exports.getBaseTemplate = getBaseTemplate;
|
|
3318
3866
|
exports.getEngineName = getEngineName;
|
|
3319
3867
|
exports.getLanguageFromTemplate = getLanguageFromTemplate;
|
|
@@ -3325,12 +3873,32 @@ exports.getLatestPnpmVersion = getLatestPnpmVersion;
|
|
|
3325
3873
|
exports.getLatestYarnVersion = getLatestYarnVersion;
|
|
3326
3874
|
exports.getPackageManagerName = getPackageManagerName;
|
|
3327
3875
|
exports.getResolvedPackageVersion = getResolvedPackageVersion;
|
|
3328
|
-
exports.
|
|
3876
|
+
exports.merge = merge;
|
|
3877
|
+
exports.mergePackageJsonScripts = mergePackageJsonScripts;
|
|
3878
|
+
exports.packageJsonScripts = packageJsonScripts;
|
|
3329
3879
|
exports.parseEngine = parseEngine;
|
|
3330
3880
|
exports.parsePackageManager = parsePackageManager;
|
|
3331
3881
|
exports.parseWorkspaceYamlContent = parseWorkspaceYamlContent;
|
|
3332
|
-
exports.
|
|
3882
|
+
exports.planProject = planProject;
|
|
3883
|
+
exports.planWorkspace = planWorkspace;
|
|
3884
|
+
exports.projectPlanInputToOptions = projectPlanInputToOptions;
|
|
3885
|
+
exports.renderAiFiles = renderAiFiles;
|
|
3886
|
+
exports.renderEditorConfig = renderEditorConfig;
|
|
3887
|
+
exports.renderEslintConfigPackage = renderEslintConfigPackage;
|
|
3888
|
+
exports.renderGitignore = renderGitignore;
|
|
3889
|
+
exports.renderOxfmtConfigPackage = renderOxfmtConfigPackage;
|
|
3890
|
+
exports.renderOxlintConfig = renderOxlintConfig;
|
|
3891
|
+
exports.renderOxlintConfigPackage = renderOxlintConfigPackage;
|
|
3892
|
+
exports.renderPrettierConfigPackage = renderPrettierConfigPackage;
|
|
3893
|
+
exports.renderTypescriptConfigPackage = renderTypescriptConfigPackage;
|
|
3894
|
+
exports.renderViteConfig = renderViteConfig;
|
|
3895
|
+
exports.renderVscodeFiles = renderVscodeFiles;
|
|
3896
|
+
exports.renderVscodeFiles$1 = renderVscodeFiles$1;
|
|
3897
|
+
exports.resolveDefaultPackageJsonScripts = resolveDefaultPackageJsonScripts;
|
|
3333
3898
|
exports.resolveMonorepoRootPackageVersions = resolveMonorepoRootPackageVersions;
|
|
3334
|
-
exports.
|
|
3335
|
-
exports.
|
|
3899
|
+
exports.resolveProjectPlanInput = resolveProjectPlanInput;
|
|
3900
|
+
exports.resolveWorkspacePlanInput = resolveWorkspacePlanInput;
|
|
3901
|
+
exports.toPrettierIgnoreContent = toPrettierIgnoreContent;
|
|
3902
|
+
exports.unique = unique;
|
|
3336
3903
|
exports.validatePackageName = validatePackageName;
|
|
3904
|
+
exports.workspacePlanInputToMonorepoParams = workspacePlanInputToMonorepoParams;
|