create-krispya 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -6
- package/dist/cli.cjs +1302 -1576
- package/dist/cli.d.cts +36 -0
- package/dist/cli.d.mts +36 -0
- package/dist/cli.d.ts +36 -0
- package/dist/cli.mjs +1326 -1600
- package/dist/index.cjs +52 -15
- package/dist/index.d.cts +81 -172
- package/dist/index.d.mts +81 -172
- package/dist/index.d.ts +81 -172
- package/dist/index.mjs +34 -1
- package/dist/{chunks/index.mjs → shared/create-krispya.DKKVmsqH.mjs} +1358 -741
- package/dist/{chunks/index.cjs → shared/create-krispya.DTHeUlq4.cjs} +1381 -754
- package/dist/shared/create-krispya.to8NBxeJ.d.cts +237 -0
- package/dist/shared/create-krispya.to8NBxeJ.d.mts +237 -0
- package/dist/shared/create-krispya.to8NBxeJ.d.ts +237 -0
- package/package.json +7 -3
|
@@ -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,37 +184,51 @@ function getBaseTemplate(template) {
|
|
|
201
184
|
return template.replace("-js", "");
|
|
202
185
|
}
|
|
203
186
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
return fallback;
|
|
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);
|
|
192
|
+
}
|
|
211
193
|
}
|
|
194
|
+
return Array.from(set);
|
|
212
195
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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(
|
|
202
|
+
`Cannot merge "${modificationLabel}" modification into target "${targetLabel}"`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
if (target == null) {
|
|
206
|
+
return modification;
|
|
207
|
+
}
|
|
208
|
+
if (Array.isArray(target)) {
|
|
209
|
+
if (!Array.isArray(modification)) {
|
|
210
|
+
throw new Error(
|
|
211
|
+
`Cannot merge non-array modification "${modificationLabel}" into array target "${targetLabel}"`
|
|
212
|
+
);
|
|
229
213
|
}
|
|
230
|
-
return
|
|
231
|
-
}
|
|
232
|
-
|
|
214
|
+
return [...target, ...modification];
|
|
215
|
+
}
|
|
216
|
+
if (typeof target === "object") {
|
|
217
|
+
if (typeof modification !== "object") {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`Cannot merge non-object modification "${modificationLabel}" into object target "${targetLabel}"`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
const result = { ...target };
|
|
223
|
+
for (const modificationKey in modification) {
|
|
224
|
+
result[modificationKey] = merge(target[modificationKey], modification[modificationKey]);
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
233
227
|
}
|
|
228
|
+
console.warn(`target "${targetLabel}" is overwritten with modification "${modificationLabel}"`);
|
|
229
|
+
return modification;
|
|
234
230
|
}
|
|
231
|
+
|
|
235
232
|
function validateNameSegment(segment, label) {
|
|
236
233
|
if (!segment.length) {
|
|
237
234
|
return `${label} is required`;
|
|
@@ -275,103 +272,7 @@ function validatePackageName(name) {
|
|
|
275
272
|
}
|
|
276
273
|
return validateNameSegment(name, "Package name");
|
|
277
274
|
}
|
|
278
|
-
|
|
279
|
-
const directories = [];
|
|
280
|
-
let inPackagesSection = false;
|
|
281
|
-
for (const line of content.split("\n")) {
|
|
282
|
-
const trimmed = line.trim();
|
|
283
|
-
if (trimmed === "packages:") {
|
|
284
|
-
inPackagesSection = true;
|
|
285
|
-
continue;
|
|
286
|
-
}
|
|
287
|
-
if (inPackagesSection && trimmed && !line.startsWith(" ") && !line.startsWith(" ") && !trimmed.startsWith("-")) {
|
|
288
|
-
break;
|
|
289
|
-
}
|
|
290
|
-
if (inPackagesSection && trimmed.startsWith("-")) {
|
|
291
|
-
const entry = trimmed.slice(1).trim().replace(/^["']|["']$/g, "").replace(/^\.\//, "").replace(/\/\*.*$/, "");
|
|
292
|
-
if (entry && !entry.startsWith(".")) {
|
|
293
|
-
directories.push(entry);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return directories;
|
|
298
|
-
}
|
|
299
|
-
async function pathExists(path) {
|
|
300
|
-
try {
|
|
301
|
-
await promises.access(path, fs.constants.F_OK);
|
|
302
|
-
return true;
|
|
303
|
-
} catch {
|
|
304
|
-
return false;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
function detectLinterFromScript(script) {
|
|
308
|
-
if (!script) return void 0;
|
|
309
|
-
if (script.includes("oxlint")) return "oxlint";
|
|
310
|
-
if (script.includes("eslint")) return "eslint";
|
|
311
|
-
if (script.includes("biome check") || script.includes("biome lint")) return "biome";
|
|
312
|
-
return void 0;
|
|
313
|
-
}
|
|
314
|
-
function detectFormatterFromScript(script) {
|
|
315
|
-
if (!script) return void 0;
|
|
316
|
-
if (script.includes("prettier")) return "prettier";
|
|
317
|
-
if (script.includes("oxfmt")) return "oxfmt";
|
|
318
|
-
if (script.includes("biome format")) return "biome";
|
|
319
|
-
return void 0;
|
|
320
|
-
}
|
|
321
|
-
async function detectLinterFromConfig(root) {
|
|
322
|
-
if (await pathExists(path.join(root, ".config/oxlint"))) return "oxlint";
|
|
323
|
-
if (await pathExists(path.join(root, ".config/eslint"))) return "eslint";
|
|
324
|
-
if (await pathExists(path.join(root, "biome.json"))) {
|
|
325
|
-
try {
|
|
326
|
-
const content = await promises.readFile(path.join(root, "biome.json"), "utf-8");
|
|
327
|
-
const config = JSON.parse(content);
|
|
328
|
-
if (config.linter?.enabled !== false) return "biome";
|
|
329
|
-
} catch {
|
|
330
|
-
return "biome";
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
return void 0;
|
|
334
|
-
}
|
|
335
|
-
async function detectFormatterFromConfig(root) {
|
|
336
|
-
if (await pathExists(path.join(root, ".config/prettier"))) return "prettier";
|
|
337
|
-
if (await pathExists(path.join(root, ".config/oxfmt"))) return "oxfmt";
|
|
338
|
-
if (await pathExists(path.join(root, "biome.json"))) {
|
|
339
|
-
try {
|
|
340
|
-
const content = await promises.readFile(path.join(root, "biome.json"), "utf-8");
|
|
341
|
-
const config = JSON.parse(content);
|
|
342
|
-
if (config.formatter?.enabled !== false) return "biome";
|
|
343
|
-
} catch {
|
|
344
|
-
return "biome";
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
return void 0;
|
|
348
|
-
}
|
|
349
|
-
function detectLinterFromDeps(devDeps) {
|
|
350
|
-
if (!devDeps) return void 0;
|
|
351
|
-
if (devDeps["@biomejs/biome"]) return "biome";
|
|
352
|
-
if (devDeps.eslint) return "eslint";
|
|
353
|
-
if (devDeps.oxlint) return "oxlint";
|
|
354
|
-
return void 0;
|
|
355
|
-
}
|
|
356
|
-
function detectFormatterFromDeps(devDeps) {
|
|
357
|
-
if (!devDeps) return void 0;
|
|
358
|
-
if (devDeps["@biomejs/biome"]) return "biome";
|
|
359
|
-
if (devDeps.prettier) return "prettier";
|
|
360
|
-
if (devDeps.oxfmt) return "oxfmt";
|
|
361
|
-
return void 0;
|
|
362
|
-
}
|
|
363
|
-
async function detectTooling(root) {
|
|
364
|
-
try {
|
|
365
|
-
const pkgPath = path.join(root, "package.json");
|
|
366
|
-
const content = await promises.readFile(pkgPath, "utf-8");
|
|
367
|
-
const pkg = JSON.parse(content);
|
|
368
|
-
const linter = detectLinterFromScript(pkg.scripts?.lint) ?? await detectLinterFromConfig(root) ?? detectLinterFromDeps(pkg.devDependencies);
|
|
369
|
-
const formatter = detectFormatterFromScript(pkg.scripts?.format) ?? await detectFormatterFromConfig(root) ?? detectFormatterFromDeps(pkg.devDependencies);
|
|
370
|
-
return { linter, formatter };
|
|
371
|
-
} catch {
|
|
372
|
-
return { linter: void 0, formatter: void 0 };
|
|
373
|
-
}
|
|
374
|
-
}
|
|
275
|
+
|
|
375
276
|
function generateRandomName() {
|
|
376
277
|
const adjectives = [
|
|
377
278
|
"red",
|
|
@@ -448,6 +349,159 @@ function generateRandomName() {
|
|
|
448
349
|
return `${randomAdjective}-${randomNoun}`;
|
|
449
350
|
}
|
|
450
351
|
|
|
352
|
+
async function pathExists(path) {
|
|
353
|
+
try {
|
|
354
|
+
await promises.access(path, fs.constants.F_OK);
|
|
355
|
+
return true;
|
|
356
|
+
} catch {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function detectLinterFromScript(script) {
|
|
361
|
+
if (!script) return void 0;
|
|
362
|
+
if (script.includes("oxlint")) return "oxlint";
|
|
363
|
+
if (script.includes("eslint")) return "eslint";
|
|
364
|
+
if (script.includes("biome check") || script.includes("biome lint")) return "biome";
|
|
365
|
+
return void 0;
|
|
366
|
+
}
|
|
367
|
+
function detectFormatterFromScript(script) {
|
|
368
|
+
if (!script) return void 0;
|
|
369
|
+
if (script.includes("prettier")) return "prettier";
|
|
370
|
+
if (script.includes("oxfmt")) return "oxfmt";
|
|
371
|
+
if (script.includes("biome format")) return "biome";
|
|
372
|
+
return void 0;
|
|
373
|
+
}
|
|
374
|
+
async function detectLinterFromConfig(root) {
|
|
375
|
+
if (await pathExists(path.join(root, ".config/oxlint"))) return "oxlint";
|
|
376
|
+
if (await pathExists(path.join(root, ".config/eslint"))) return "eslint";
|
|
377
|
+
if (await pathExists(path.join(root, "biome.json"))) {
|
|
378
|
+
try {
|
|
379
|
+
const content = await promises.readFile(path.join(root, "biome.json"), "utf-8");
|
|
380
|
+
const config = JSON.parse(content);
|
|
381
|
+
if (config.linter?.enabled !== false) return "biome";
|
|
382
|
+
} catch {
|
|
383
|
+
return "biome";
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return void 0;
|
|
387
|
+
}
|
|
388
|
+
async function detectFormatterFromConfig(root) {
|
|
389
|
+
if (await pathExists(path.join(root, ".config/prettier"))) return "prettier";
|
|
390
|
+
if (await pathExists(path.join(root, ".config/oxfmt"))) return "oxfmt";
|
|
391
|
+
if (await pathExists(path.join(root, "biome.json"))) {
|
|
392
|
+
try {
|
|
393
|
+
const content = await promises.readFile(path.join(root, "biome.json"), "utf-8");
|
|
394
|
+
const config = JSON.parse(content);
|
|
395
|
+
if (config.formatter?.enabled !== false) return "biome";
|
|
396
|
+
} catch {
|
|
397
|
+
return "biome";
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return void 0;
|
|
401
|
+
}
|
|
402
|
+
function detectLinterFromDeps(devDeps) {
|
|
403
|
+
if (!devDeps) return void 0;
|
|
404
|
+
if (devDeps["@biomejs/biome"]) return "biome";
|
|
405
|
+
if (devDeps.eslint) return "eslint";
|
|
406
|
+
if (devDeps.oxlint) return "oxlint";
|
|
407
|
+
return void 0;
|
|
408
|
+
}
|
|
409
|
+
function detectFormatterFromDeps(devDeps) {
|
|
410
|
+
if (!devDeps) return void 0;
|
|
411
|
+
if (devDeps["@biomejs/biome"]) return "biome";
|
|
412
|
+
if (devDeps.prettier) return "prettier";
|
|
413
|
+
if (devDeps.oxfmt) return "oxfmt";
|
|
414
|
+
return void 0;
|
|
415
|
+
}
|
|
416
|
+
async function detectTooling(root) {
|
|
417
|
+
try {
|
|
418
|
+
const pkgPath = path.join(root, "package.json");
|
|
419
|
+
const content = await promises.readFile(pkgPath, "utf-8");
|
|
420
|
+
const pkg = JSON.parse(content);
|
|
421
|
+
const linter = detectLinterFromScript(pkg.scripts?.lint) ?? await detectLinterFromConfig(root) ?? detectLinterFromDeps(pkg.devDependencies);
|
|
422
|
+
const formatter = detectFormatterFromScript(pkg.scripts?.format) ?? await detectFormatterFromConfig(root) ?? detectFormatterFromDeps(pkg.devDependencies);
|
|
423
|
+
return { linter, formatter };
|
|
424
|
+
} catch {
|
|
425
|
+
return { linter: void 0, formatter: void 0 };
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async function getLatestNpmVersion(packageName, fallback) {
|
|
430
|
+
try {
|
|
431
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`);
|
|
432
|
+
const data = await response.json();
|
|
433
|
+
return data.version;
|
|
434
|
+
} catch {
|
|
435
|
+
return fallback;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function compareNumericSemver(a, b) {
|
|
439
|
+
const aParts = a.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
440
|
+
const bParts = b.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
441
|
+
const maxLength = Math.max(aParts.length, bParts.length);
|
|
442
|
+
for (let index = 0; index < maxLength; index += 1) {
|
|
443
|
+
const difference = (aParts[index] ?? 0) - (bParts[index] ?? 0);
|
|
444
|
+
if (difference !== 0) {
|
|
445
|
+
return difference;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return 0;
|
|
449
|
+
}
|
|
450
|
+
async function getLatestNpmMajorVersion(packageName, majorVersion, fallback) {
|
|
451
|
+
try {
|
|
452
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}`);
|
|
453
|
+
const data = await response.json();
|
|
454
|
+
const latestMatchingVersion = Object.keys(data.versions ?? {}).filter((version) => version.split(".")[0] === majorVersion).sort((a, b) => compareNumericSemver(b, a))[0];
|
|
455
|
+
return latestMatchingVersion ?? fallback;
|
|
456
|
+
} catch {
|
|
457
|
+
return fallback;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
async function getLatestPnpmVersion() {
|
|
461
|
+
return getLatestNpmVersion("pnpm", "10.11.0");
|
|
462
|
+
}
|
|
463
|
+
async function getLatestYarnVersion() {
|
|
464
|
+
return getLatestNpmVersion("yarn", "4.6.0");
|
|
465
|
+
}
|
|
466
|
+
async function getLatestNpmCliVersion() {
|
|
467
|
+
return getLatestNpmVersion("npm", "11.0.0");
|
|
468
|
+
}
|
|
469
|
+
async function getLatestNodeVersion() {
|
|
470
|
+
try {
|
|
471
|
+
const response = await fetch("https://nodejs.org/dist/index.json");
|
|
472
|
+
const data = await response.json();
|
|
473
|
+
const latestVersion = data[0];
|
|
474
|
+
if (latestVersion) {
|
|
475
|
+
return latestVersion.version.replace(/^v/, "");
|
|
476
|
+
}
|
|
477
|
+
return "25.0.0";
|
|
478
|
+
} catch {
|
|
479
|
+
return "25.0.0";
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function parseWorkspaceYamlContent(content) {
|
|
484
|
+
const directories = [];
|
|
485
|
+
let inPackagesSection = false;
|
|
486
|
+
for (const line of content.split("\n")) {
|
|
487
|
+
const trimmed = line.trim();
|
|
488
|
+
if (trimmed === "packages:") {
|
|
489
|
+
inPackagesSection = true;
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
if (inPackagesSection && trimmed && !line.startsWith(" ") && !line.startsWith(" ") && !trimmed.startsWith("-")) {
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
if (inPackagesSection && trimmed.startsWith("-")) {
|
|
496
|
+
const entry = trimmed.slice(1).trim().replace(/^["']|["']$/g, "").replace(/^\.\//, "").replace(/\/\*.*$/, "");
|
|
497
|
+
if (entry && !entry.startsWith(".")) {
|
|
498
|
+
directories.push(entry);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return directories;
|
|
503
|
+
}
|
|
504
|
+
|
|
451
505
|
const PACKAGE_VERSION_DEFINITIONS = {
|
|
452
506
|
"@biomejs/biome": { fallbackVersion: "2.0.0" },
|
|
453
507
|
"@react-three/drei": { fallbackVersion: "10.0.0" },
|
|
@@ -473,11 +527,13 @@ const PACKAGE_VERSION_DEFINITIONS = {
|
|
|
473
527
|
leva: { fallbackVersion: "0.10.0" },
|
|
474
528
|
oxfmt: { fallbackVersion: "0.21.0" },
|
|
475
529
|
oxlint: { fallbackVersion: "1.36.0" },
|
|
530
|
+
"oxlint-tsgolint": { fallbackVersion: "0.22.1" },
|
|
476
531
|
prettier: { fallbackVersion: "3.4.2" },
|
|
477
532
|
react: { fallbackVersion: "19.0.0" },
|
|
478
533
|
"react-dom": { fallbackVersion: "19.0.0" },
|
|
479
534
|
three: { fallbackVersion: "0.175.0", prefix: "~" },
|
|
480
535
|
tsdown: { fallbackVersion: "0.12.0" },
|
|
536
|
+
typescript: { fallbackVersion: "5.9.3" },
|
|
481
537
|
"typescript-eslint": { fallbackVersion: "8.18.0" },
|
|
482
538
|
unbuild: { fallbackVersion: "3.5.0" },
|
|
483
539
|
vite: { fallbackVersion: "6.3.4" },
|
|
@@ -569,11 +625,35 @@ async function resolvePackageManager(options) {
|
|
|
569
625
|
}
|
|
570
626
|
async function resolveEngine(options) {
|
|
571
627
|
const engine = getEngineSpec(options.engine);
|
|
572
|
-
if (engine.version == null && engine.name === "node") {
|
|
628
|
+
if ((engine.version == null || engine.version === "latest") && engine.name === "node") {
|
|
573
629
|
engine.version = await getLatestNodeVersion();
|
|
574
630
|
}
|
|
575
631
|
return engine;
|
|
576
632
|
}
|
|
633
|
+
function formatNodeTypesVersion(versions = {}, engine) {
|
|
634
|
+
const resolvedVersion = versions["@types/node"];
|
|
635
|
+
if (resolvedVersion != null) {
|
|
636
|
+
return `^${resolvedVersion}`;
|
|
637
|
+
}
|
|
638
|
+
const engineSpec = getEngineSpec(engine);
|
|
639
|
+
if (engineSpec.name === "node" && engineSpec.version) {
|
|
640
|
+
const majorVersion = engineSpec.version.split(".")[0];
|
|
641
|
+
return `^${majorVersion}.0.0`;
|
|
642
|
+
}
|
|
643
|
+
return "^22.0.0";
|
|
644
|
+
}
|
|
645
|
+
async function resolveNodeTypesVersion(engine, versions = {}) {
|
|
646
|
+
if (versions["@types/node"] != null) {
|
|
647
|
+
return versions["@types/node"];
|
|
648
|
+
}
|
|
649
|
+
const engineSpec = getEngineSpec(engine);
|
|
650
|
+
if (engineSpec.name !== "node") {
|
|
651
|
+
return void 0;
|
|
652
|
+
}
|
|
653
|
+
const nodeVersion = engineSpec.version ?? await getLatestNodeVersion();
|
|
654
|
+
const majorVersion = nodeVersion.split(".")[0];
|
|
655
|
+
return getLatestNpmMajorVersion("@types/node", majorVersion, `${majorVersion}.0.0`);
|
|
656
|
+
}
|
|
577
657
|
async function resolvePackageVersions(packageNames, existingVersions = {}) {
|
|
578
658
|
const versions = { ...existingVersions };
|
|
579
659
|
const uniquePackageNames = [...new Set(packageNames)];
|
|
@@ -589,16 +669,33 @@ async function resolvePackageVersions(packageNames, existingVersions = {}) {
|
|
|
589
669
|
return versions;
|
|
590
670
|
}
|
|
591
671
|
async function resolveProjectPackageVersions(options) {
|
|
592
|
-
|
|
672
|
+
const packageNames = collectProjectPackageNames(options);
|
|
673
|
+
const versions = await resolvePackageVersions(
|
|
674
|
+
packageNames.filter((packageName) => packageName !== "@types/node"),
|
|
675
|
+
options.versions
|
|
676
|
+
);
|
|
677
|
+
const nodeTypesVersion = await resolveNodeTypesVersion(options.engine, versions);
|
|
678
|
+
if (nodeTypesVersion != null) {
|
|
679
|
+
versions["@types/node"] = nodeTypesVersion;
|
|
680
|
+
}
|
|
681
|
+
return versions;
|
|
593
682
|
}
|
|
594
683
|
async function resolveMonorepoRootPackageVersions(params) {
|
|
595
684
|
const packageNames = /* @__PURE__ */ new Set();
|
|
596
685
|
const explicitVersions = new Set(Object.keys(params.versions ?? {}));
|
|
597
686
|
addPackageName(packageNames, explicitVersions, getLinterPackage(params.linter));
|
|
687
|
+
if (params.linter === "oxlint") {
|
|
688
|
+
addPackageName(packageNames, explicitVersions, "oxlint-tsgolint");
|
|
689
|
+
}
|
|
598
690
|
if (params.formatter !== "biome" || params.linter !== "biome") {
|
|
599
691
|
addPackageName(packageNames, explicitVersions, getFormatterPackage(params.formatter));
|
|
600
692
|
}
|
|
601
|
-
|
|
693
|
+
const versions = await resolvePackageVersions(packageNames, params.versions);
|
|
694
|
+
const nodeTypesVersion = await resolveNodeTypesVersion(params.engine, versions);
|
|
695
|
+
if (nodeTypesVersion != null) {
|
|
696
|
+
versions["@types/node"] = nodeTypesVersion;
|
|
697
|
+
}
|
|
698
|
+
return versions;
|
|
602
699
|
}
|
|
603
700
|
function collectProjectPackageNames(options) {
|
|
604
701
|
const packageNames = /* @__PURE__ */ new Set();
|
|
@@ -616,6 +713,13 @@ function collectProjectPackageNames(options) {
|
|
|
616
713
|
const formatter = options.formatter ?? "prettier";
|
|
617
714
|
const bundler = options.libraryBundler ?? "unbuild";
|
|
618
715
|
const packageManager = getPackageManagerName(options.packageManager);
|
|
716
|
+
const engine = getEngineSpec(options.engine);
|
|
717
|
+
if (getEngineName(engine) === "node") {
|
|
718
|
+
addPackageName(packageNames, explicitVersions, "@types/node");
|
|
719
|
+
}
|
|
720
|
+
if (isTypescript) {
|
|
721
|
+
addPackageName(packageNames, explicitVersions, "typescript");
|
|
722
|
+
}
|
|
619
723
|
if (!isLibrary) {
|
|
620
724
|
addPackageName(packageNames, explicitVersions, "vite");
|
|
621
725
|
}
|
|
@@ -692,6 +796,9 @@ function collectProjectPackageNames(options) {
|
|
|
692
796
|
} else if (linter === "oxlint") {
|
|
693
797
|
if (!inWorkspace) {
|
|
694
798
|
addPackageName(packageNames, explicitVersions, "oxlint");
|
|
799
|
+
if (isTypescript) {
|
|
800
|
+
addPackageName(packageNames, explicitVersions, "oxlint-tsgolint");
|
|
801
|
+
}
|
|
695
802
|
}
|
|
696
803
|
} else if (linter === "biome") {
|
|
697
804
|
addPackageName(packageNames, explicitVersions, "@biomejs/biome");
|
|
@@ -726,7 +833,7 @@ function isEnabledOption(option) {
|
|
|
726
833
|
return option != null && option !== false;
|
|
727
834
|
}
|
|
728
835
|
|
|
729
|
-
function
|
|
836
|
+
function renderTypescriptConfig(baseTemplateOrParams) {
|
|
730
837
|
const params = typeof baseTemplateOrParams === "string" ? { baseTemplate: baseTemplateOrParams } : baseTemplateOrParams;
|
|
731
838
|
const {
|
|
732
839
|
baseTemplate,
|
|
@@ -739,9 +846,9 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
739
846
|
const isR3f = baseTemplate === "r3f";
|
|
740
847
|
const files = {};
|
|
741
848
|
const devDependencies = {};
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
devDependencies["@types/node"] =
|
|
849
|
+
assignResolvedPackageVersion(devDependencies, versions, "typescript");
|
|
850
|
+
if (getEngineName(engine) === "node") {
|
|
851
|
+
devDependencies["@types/node"] = formatNodeTypesVersion(versions, engine);
|
|
745
852
|
} else {
|
|
746
853
|
devDependencies["@types/node"] = "^22.0.0";
|
|
747
854
|
}
|
|
@@ -796,6 +903,7 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
796
903
|
composite: true,
|
|
797
904
|
rewriteRelativeImportExtensions: true,
|
|
798
905
|
erasableSyntaxOnly: true,
|
|
906
|
+
noEmit: true,
|
|
799
907
|
...isReact || isR3f ? { jsx: "react-jsx" } : {}
|
|
800
908
|
},
|
|
801
909
|
include: ["../src", "../tests"]
|
|
@@ -817,7 +925,8 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
817
925
|
skipLibCheck: true,
|
|
818
926
|
composite: true,
|
|
819
927
|
rewriteRelativeImportExtensions: true,
|
|
820
|
-
erasableSyntaxOnly: true
|
|
928
|
+
erasableSyntaxOnly: true,
|
|
929
|
+
noEmit: true
|
|
821
930
|
},
|
|
822
931
|
include: ["../*.config.ts", "./*.ts"]
|
|
823
932
|
};
|
|
@@ -849,6 +958,7 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
849
958
|
composite: true,
|
|
850
959
|
rewriteRelativeImportExtensions: true,
|
|
851
960
|
erasableSyntaxOnly: true,
|
|
961
|
+
noEmit: true,
|
|
852
962
|
...isReact || isR3f ? { jsx: "react-jsx" } : {}
|
|
853
963
|
},
|
|
854
964
|
include: ["src", "tests"]
|
|
@@ -870,7 +980,8 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
870
980
|
skipLibCheck: true,
|
|
871
981
|
composite: true,
|
|
872
982
|
rewriteRelativeImportExtensions: true,
|
|
873
|
-
erasableSyntaxOnly: true
|
|
983
|
+
erasableSyntaxOnly: true,
|
|
984
|
+
noEmit: true
|
|
874
985
|
},
|
|
875
986
|
include: ["*.config.ts"]
|
|
876
987
|
};
|
|
@@ -882,8 +993,108 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
882
993
|
return { files, devDependencies };
|
|
883
994
|
}
|
|
884
995
|
|
|
996
|
+
const packageJsonScripts = {
|
|
997
|
+
appBase: {
|
|
998
|
+
dev: "vite",
|
|
999
|
+
build: "vite build"
|
|
1000
|
+
},
|
|
1001
|
+
typescript: {
|
|
1002
|
+
typecheck: "tsc --build --noEmit",
|
|
1003
|
+
"typecheck:watch": "tsc --build --watch"
|
|
1004
|
+
},
|
|
1005
|
+
test: {
|
|
1006
|
+
vitest: {
|
|
1007
|
+
test: "vitest"
|
|
1008
|
+
}
|
|
1009
|
+
},
|
|
1010
|
+
build: {
|
|
1011
|
+
unbuild(configPath) {
|
|
1012
|
+
return {
|
|
1013
|
+
build: configPath == null ? "unbuild" : `unbuild --config ${configPath}`
|
|
1014
|
+
};
|
|
1015
|
+
},
|
|
1016
|
+
tsdown: {
|
|
1017
|
+
build: "tsdown"
|
|
1018
|
+
}
|
|
1019
|
+
},
|
|
1020
|
+
lint: {
|
|
1021
|
+
oxlint(configPath) {
|
|
1022
|
+
return {
|
|
1023
|
+
lint: configPath == null ? "oxlint" : `oxlint -c ${configPath}`
|
|
1024
|
+
};
|
|
1025
|
+
},
|
|
1026
|
+
eslint(configPath) {
|
|
1027
|
+
return {
|
|
1028
|
+
lint: configPath == null ? "eslint ." : `eslint --config ${configPath} .`
|
|
1029
|
+
};
|
|
1030
|
+
},
|
|
1031
|
+
biome(configPath) {
|
|
1032
|
+
return {
|
|
1033
|
+
lint: configPath == null ? "biome lint ." : `biome lint --config-path ${configPath} .`
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
},
|
|
1037
|
+
format: {
|
|
1038
|
+
prettier(configPath, ignorePath) {
|
|
1039
|
+
const configFlag = configPath == null ? "" : ` --config ${configPath}`;
|
|
1040
|
+
const ignoreFlag = ignorePath == null ? "" : ` --ignore-path ${ignorePath}`;
|
|
1041
|
+
return {
|
|
1042
|
+
format: `prettier${configFlag}${ignoreFlag} --write .`
|
|
1043
|
+
};
|
|
1044
|
+
},
|
|
1045
|
+
oxfmt(configPath) {
|
|
1046
|
+
return {
|
|
1047
|
+
format: `oxfmt -c ${configPath} --write .`
|
|
1048
|
+
};
|
|
1049
|
+
},
|
|
1050
|
+
biome(configPath) {
|
|
1051
|
+
return {
|
|
1052
|
+
format: configPath == null ? "biome format --write ." : `biome format --config-path ${configPath} --write .`
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
},
|
|
1056
|
+
release(packageManagerName) {
|
|
1057
|
+
return {
|
|
1058
|
+
release: `${packageManagerName} run build && ${packageManagerName} publish`
|
|
1059
|
+
};
|
|
1060
|
+
},
|
|
1061
|
+
monorepoRoot(linter, formatter) {
|
|
1062
|
+
return mergePackageJsonScripts(
|
|
1063
|
+
{
|
|
1064
|
+
dev: "pnpm --filter './apps/*' run dev",
|
|
1065
|
+
build: "pnpm --filter './packages/*' run build && pnpm --filter './apps/*' run build",
|
|
1066
|
+
test: "pnpm -r run test"
|
|
1067
|
+
},
|
|
1068
|
+
linter === "oxlint" ? {
|
|
1069
|
+
lint: "oxlint ."
|
|
1070
|
+
} : linter === "biome" ? {
|
|
1071
|
+
lint: "biome check ."
|
|
1072
|
+
} : {
|
|
1073
|
+
lint: "eslint ."
|
|
1074
|
+
},
|
|
1075
|
+
formatter === "oxfmt" ? {
|
|
1076
|
+
format: "oxfmt -c .config/oxfmt/base.json ."
|
|
1077
|
+
} : formatter === "biome" ? {
|
|
1078
|
+
format: "biome format . --write"
|
|
1079
|
+
} : {
|
|
1080
|
+
format: "prettier --config .config/prettier/base.json --ignore-path .config/prettier/prettierignore --write ."
|
|
1081
|
+
}
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
function mergePackageJsonScripts(...scriptSets) {
|
|
1086
|
+
return Object.assign({}, ...scriptSets.filter((scriptSet) => scriptSet != null));
|
|
1087
|
+
}
|
|
1088
|
+
function resolveDefaultPackageJsonScripts(params) {
|
|
1089
|
+
return mergePackageJsonScripts(
|
|
1090
|
+
params.isLibrary ? void 0 : packageJsonScripts.appBase,
|
|
1091
|
+
params.language === "typescript" ? packageJsonScripts.typescript : void 0,
|
|
1092
|
+
params.isLibrary ? packageJsonScripts.release(params.packageManagerName) : void 0
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
885
1096
|
const DEFAULT_LIBRARY_VERSION = "0.1.0";
|
|
886
|
-
function
|
|
1097
|
+
function renderPackageJson(params) {
|
|
887
1098
|
const {
|
|
888
1099
|
name,
|
|
889
1100
|
language,
|
|
@@ -891,13 +1102,20 @@ function generatePackageJson(params) {
|
|
|
891
1102
|
dependencies,
|
|
892
1103
|
devDependencies,
|
|
893
1104
|
peerDependencies,
|
|
894
|
-
scripts,
|
|
895
1105
|
options,
|
|
896
1106
|
workspaceDependencies
|
|
897
1107
|
} = params;
|
|
898
1108
|
const files = {};
|
|
899
1109
|
const packageManager = getPackageManagerSpec(options.packageManager);
|
|
900
1110
|
const isPnpm = packageManager.name === "pnpm";
|
|
1111
|
+
const resolvedScripts = mergePackageJsonScripts(
|
|
1112
|
+
resolveDefaultPackageJsonScripts({
|
|
1113
|
+
language,
|
|
1114
|
+
isLibrary,
|
|
1115
|
+
packageManagerName: packageManager.name
|
|
1116
|
+
}),
|
|
1117
|
+
params.scripts
|
|
1118
|
+
);
|
|
901
1119
|
const packageJson = {
|
|
902
1120
|
name,
|
|
903
1121
|
description: "Built with \u{1F339} create-krispya",
|
|
@@ -929,10 +1147,12 @@ function generatePackageJson(params) {
|
|
|
929
1147
|
const allDevDependencies = { ...devDependencies };
|
|
930
1148
|
const engine = getEngineSpec(options.engine);
|
|
931
1149
|
if (getEngineName(engine) === "node" && engine.version) {
|
|
932
|
-
|
|
933
|
-
|
|
1150
|
+
allDevDependencies["@types/node"] ??= formatNodeTypesVersion(
|
|
1151
|
+
options.versions,
|
|
1152
|
+
options.engine
|
|
1153
|
+
);
|
|
934
1154
|
}
|
|
935
|
-
packageJson.scripts =
|
|
1155
|
+
packageJson.scripts = resolvedScripts;
|
|
936
1156
|
packageJson.dependencies = sortKeys(allDependencies);
|
|
937
1157
|
if (Object.keys(allDevDependencies).length > 0) {
|
|
938
1158
|
packageJson.devDependencies = sortKeys(allDevDependencies);
|
|
@@ -975,7 +1195,7 @@ function generatePackageJson(params) {
|
|
|
975
1195
|
return { files };
|
|
976
1196
|
}
|
|
977
1197
|
|
|
978
|
-
function
|
|
1198
|
+
function renderReadme(params) {
|
|
979
1199
|
const { name, baseTemplate, isLibrary, libraryBundler, packageManager, codeSnippets } = params;
|
|
980
1200
|
const isVanilla = baseTemplate === "vanilla";
|
|
981
1201
|
const isReact = baseTemplate === "react";
|
|
@@ -1068,7 +1288,63 @@ function generateReadme(params) {
|
|
|
1068
1288
|
return { type: "text", content };
|
|
1069
1289
|
}
|
|
1070
1290
|
|
|
1071
|
-
|
|
1291
|
+
const htmlContent = `<!DOCTYPE html>
|
|
1292
|
+
<html lang="en">
|
|
1293
|
+
<head>
|
|
1294
|
+
<meta charset="UTF-8">
|
|
1295
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1296
|
+
<title>$title</title>
|
|
1297
|
+
</head>
|
|
1298
|
+
<body style="margin: 0; overscroll-behavior: none; user-select: none; touch-action: none;">
|
|
1299
|
+
<script type="module" src="$indexPath"><\/script>
|
|
1300
|
+
<div style="width: 100dvw; height: 100dvh; overflow: hidden;" id="root"></div>
|
|
1301
|
+
</body>
|
|
1302
|
+
</html>`;
|
|
1303
|
+
const viteHtmlContent = `<!DOCTYPE html>
|
|
1304
|
+
<html lang="en">
|
|
1305
|
+
<head>
|
|
1306
|
+
<meta charset="UTF-8">
|
|
1307
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1308
|
+
<title>$title</title>
|
|
1309
|
+
</head>
|
|
1310
|
+
<body>
|
|
1311
|
+
<div id="app"></div>
|
|
1312
|
+
<script type="module" src="$indexPath"><\/script>
|
|
1313
|
+
</body>
|
|
1314
|
+
</html>`;
|
|
1315
|
+
const indexContent = `import { StrictMode } from 'react'
|
|
1316
|
+
import { createRoot } from 'react-dom/client'
|
|
1317
|
+
import { App } from './app.js'
|
|
1318
|
+
|
|
1319
|
+
createRoot(document.getElementById('root')!).render(
|
|
1320
|
+
<StrictMode>
|
|
1321
|
+
<App />
|
|
1322
|
+
</StrictMode>,
|
|
1323
|
+
)`;
|
|
1324
|
+
const viteIndexContent = `import './style.css'
|
|
1325
|
+
|
|
1326
|
+
document.querySelector('#app')!.innerHTML = \`
|
|
1327
|
+
<h1>Hello Vite!</h1>
|
|
1328
|
+
<p>Edit src/main.ts and save to see HMR in action.</p>
|
|
1329
|
+
\``;
|
|
1330
|
+
const viteStyleContent = `body {
|
|
1331
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
1332
|
+
margin: 0;
|
|
1333
|
+
padding: 2rem;
|
|
1334
|
+
min-height: 100vh;
|
|
1335
|
+
background: #1a1a1a;
|
|
1336
|
+
color: #fff;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
h1 {
|
|
1340
|
+
color: #646cff;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
a {
|
|
1344
|
+
color: #646cff;
|
|
1345
|
+
}`;
|
|
1346
|
+
|
|
1347
|
+
function renderSourceFiles(params) {
|
|
1072
1348
|
const { name, baseTemplate, language, isLibrary, codeSnippets, replacements } = params;
|
|
1073
1349
|
const files = {};
|
|
1074
1350
|
const ext = language === "typescript" ? "ts" : "js";
|
|
@@ -1108,19 +1384,13 @@ function generateSourceFiles(params) {
|
|
|
1108
1384
|
}
|
|
1109
1385
|
files[`src/index.${libExt}`] = { type: "text", content: libContent };
|
|
1110
1386
|
} else if (isVanilla) {
|
|
1111
|
-
files[`src/main.${ext}`] = { type: "text", content:
|
|
1112
|
-
files["src/style.css"] = { type: "text", content:
|
|
1113
|
-
const indexHtml =
|
|
1114
|
-
"$title",
|
|
1115
|
-
name
|
|
1116
|
-
);
|
|
1387
|
+
files[`src/main.${ext}`] = { type: "text", content: viteIndexContent };
|
|
1388
|
+
files["src/style.css"] = { type: "text", content: viteStyleContent };
|
|
1389
|
+
const indexHtml = viteHtmlContent.replace("$indexPath", `./src/main.${ext}`).replace("$title", name);
|
|
1117
1390
|
files["index.html"] = { type: "text", content: indexHtml };
|
|
1118
1391
|
} else {
|
|
1119
|
-
files[`src/index.tsx`] = { type: "text", content:
|
|
1120
|
-
const indexHtml =
|
|
1121
|
-
"$indexPath",
|
|
1122
|
-
language === "javascript" ? "./src/index.jsx" : "./src/index.tsx"
|
|
1123
|
-
).replace("$title", name);
|
|
1392
|
+
files[`src/index.tsx`] = { type: "text", content: indexContent };
|
|
1393
|
+
const indexHtml = htmlContent.replace("$indexPath", language === "javascript" ? "./src/index.jsx" : "./src/index.tsx").replace("$title", name);
|
|
1124
1394
|
files["index.html"] = { type: "text", content: indexHtml };
|
|
1125
1395
|
codeSnippets["dom-end"]?.reverse();
|
|
1126
1396
|
codeSnippets["global-end"]?.reverse();
|
|
@@ -1167,7 +1437,7 @@ function generateSourceFiles(params) {
|
|
|
1167
1437
|
return files;
|
|
1168
1438
|
}
|
|
1169
1439
|
|
|
1170
|
-
function
|
|
1440
|
+
function renderTestFiles(params) {
|
|
1171
1441
|
const { baseTemplate, language, isLibrary } = params;
|
|
1172
1442
|
const files = {};
|
|
1173
1443
|
const ext = language === "typescript" ? "ts" : "js";
|
|
@@ -1274,21 +1544,184 @@ const COMMON_GITIGNORE_LINES = [
|
|
|
1274
1544
|
"*.tsbuildinfo",
|
|
1275
1545
|
".env",
|
|
1276
1546
|
".env.*",
|
|
1277
|
-
"!.env.example"
|
|
1547
|
+
"!.env.example",
|
|
1548
|
+
".pnpm-store"
|
|
1278
1549
|
];
|
|
1279
|
-
function
|
|
1550
|
+
function renderGitignore(variant) {
|
|
1280
1551
|
const lines = variant === "workspace-root" ? [...COMMON_GITIGNORE_LINES, ".DS_Store"] : COMMON_GITIGNORE_LINES;
|
|
1281
1552
|
return {
|
|
1282
1553
|
type: "text",
|
|
1283
1554
|
content: lines.join("\n")
|
|
1284
1555
|
};
|
|
1285
1556
|
}
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1557
|
+
|
|
1558
|
+
const defaultFormatterMetaConfig = {
|
|
1559
|
+
printWidth: 102,
|
|
1560
|
+
tabWidth: 2,
|
|
1561
|
+
useTabs: false,
|
|
1562
|
+
semi: true,
|
|
1563
|
+
singleQuote: true,
|
|
1564
|
+
trailingComma: "es5",
|
|
1565
|
+
bracketSpacing: true,
|
|
1566
|
+
arrowParens: "always",
|
|
1567
|
+
ignorePatterns: [
|
|
1568
|
+
"package-lock.json",
|
|
1569
|
+
"npm-shrinkwrap.json",
|
|
1570
|
+
"pnpm-lock.yaml",
|
|
1571
|
+
"pnpm-lock.json",
|
|
1572
|
+
"yarn.lock",
|
|
1573
|
+
"bun.lock",
|
|
1574
|
+
"bun.lockb"
|
|
1575
|
+
]
|
|
1576
|
+
};
|
|
1577
|
+
|
|
1578
|
+
function renderEditorConfig(config = defaultFormatterMetaConfig) {
|
|
1579
|
+
const indentStyle = config.useTabs ? "tab" : "space";
|
|
1580
|
+
const indentSize = config.useTabs ? "tab" : String(config.tabWidth);
|
|
1581
|
+
return {
|
|
1582
|
+
type: "text",
|
|
1583
|
+
content: [
|
|
1584
|
+
"root = true",
|
|
1585
|
+
"",
|
|
1586
|
+
"[*]",
|
|
1587
|
+
"charset = utf-8",
|
|
1588
|
+
"end_of_line = lf",
|
|
1589
|
+
"insert_final_newline = true",
|
|
1590
|
+
`indent_style = ${indentStyle}`,
|
|
1591
|
+
`indent_size = ${indentSize}`,
|
|
1592
|
+
`tab_width = ${config.tabWidth}`,
|
|
1593
|
+
`max_line_length = ${config.printWidth}`
|
|
1594
|
+
].join("\n")
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
function renderVscodeEditorSettings(config = defaultFormatterMetaConfig) {
|
|
1598
|
+
return {
|
|
1599
|
+
"editor.detectIndentation": false,
|
|
1600
|
+
"editor.insertSpaces": !config.useTabs,
|
|
1601
|
+
"editor.tabSize": config.tabWidth,
|
|
1602
|
+
"files.eol": "\n",
|
|
1603
|
+
"files.insertFinalNewline": true
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
const DEFAULT_VSCODE_SETTINGS = {
|
|
1608
|
+
...renderVscodeEditorSettings(),
|
|
1609
|
+
"explorer.fileNesting.enabled": true,
|
|
1610
|
+
"explorer.fileNesting.expand": false,
|
|
1611
|
+
"explorer.fileNesting.patterns": {
|
|
1612
|
+
".gitignore": ".gitattributes",
|
|
1613
|
+
"AGENTS.md": "CLAUDE.md"
|
|
1614
|
+
}
|
|
1615
|
+
};
|
|
1616
|
+
const OXFMT_LANGUAGE_SETTINGS = {
|
|
1617
|
+
"[json]": {
|
|
1618
|
+
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1619
|
+
},
|
|
1620
|
+
"[jsonc]": {
|
|
1621
|
+
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1622
|
+
},
|
|
1623
|
+
"[markdown]": {
|
|
1624
|
+
"editor.defaultFormatter": "vscode.markdown-language-features"
|
|
1625
|
+
},
|
|
1626
|
+
"[yaml]": {
|
|
1627
|
+
"editor.defaultFormatter": "redhat.vscode-yaml"
|
|
1628
|
+
}
|
|
1629
|
+
};
|
|
1630
|
+
function resolvePackageJsonNestedFiles(packageManager) {
|
|
1631
|
+
if (packageManager === "pnpm") {
|
|
1632
|
+
return ["pnpm-lock.yaml", "pnpm-workspace.yaml"];
|
|
1633
|
+
}
|
|
1634
|
+
if (packageManager === "npm") {
|
|
1635
|
+
return ["package-lock.json", "npm-shrinkwrap.json"];
|
|
1636
|
+
}
|
|
1637
|
+
if (packageManager === "yarn") {
|
|
1638
|
+
return ["yarn.lock"];
|
|
1639
|
+
}
|
|
1640
|
+
return [];
|
|
1641
|
+
}
|
|
1642
|
+
function resolveVscodeRecommendations(linter, formatter) {
|
|
1643
|
+
const recommendations = [];
|
|
1644
|
+
if (linter === "oxlint" || formatter === "oxfmt") {
|
|
1645
|
+
recommendations.push("oxc.oxc-vscode");
|
|
1646
|
+
}
|
|
1647
|
+
if (linter === "eslint") {
|
|
1648
|
+
recommendations.push("dbaeumer.vscode-eslint");
|
|
1649
|
+
}
|
|
1650
|
+
if (linter === "biome" || formatter === "biome") {
|
|
1651
|
+
recommendations.push("biomejs.biome");
|
|
1652
|
+
}
|
|
1653
|
+
if (formatter === "prettier") {
|
|
1654
|
+
recommendations.push("esbenp.prettier-vscode");
|
|
1655
|
+
}
|
|
1656
|
+
return recommendations;
|
|
1657
|
+
}
|
|
1658
|
+
function resolveVscodeSettings(params) {
|
|
1659
|
+
const { linter, formatter, configStrategy, isMonorepo, packageManager } = params;
|
|
1660
|
+
const settings = { ...DEFAULT_VSCODE_SETTINGS };
|
|
1661
|
+
const isStealth = !isMonorepo && (configStrategy ?? "stealth") === "stealth";
|
|
1662
|
+
const packageJsonNestedFiles = resolvePackageJsonNestedFiles(packageManager);
|
|
1663
|
+
if (packageJsonNestedFiles.length > 0) {
|
|
1664
|
+
settings["explorer.fileNesting.patterns"] = {
|
|
1665
|
+
...settings["explorer.fileNesting.patterns"],
|
|
1666
|
+
"package.json": packageJsonNestedFiles.join(", ")
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
if (linter === "eslint") {
|
|
1670
|
+
settings["eslint.enable"] = true;
|
|
1671
|
+
settings["oxc.enable"] = false;
|
|
1672
|
+
settings["biome.enabled"] = false;
|
|
1673
|
+
if (isStealth) {
|
|
1674
|
+
settings["eslint.options"] = {
|
|
1675
|
+
overrideConfigFile: ".config/eslint.config.js"
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
} else if (linter === "oxlint") {
|
|
1679
|
+
settings["oxc.enable"] = true;
|
|
1680
|
+
settings["eslint.enable"] = false;
|
|
1681
|
+
settings["biome.enabled"] = false;
|
|
1682
|
+
if (isStealth) {
|
|
1683
|
+
settings["oxc.configPath"] = ".config/oxlint.json";
|
|
1684
|
+
}
|
|
1685
|
+
} else if (linter === "biome") {
|
|
1686
|
+
settings["biome.enabled"] = true;
|
|
1687
|
+
settings["eslint.enable"] = false;
|
|
1688
|
+
settings["oxc.enable"] = false;
|
|
1689
|
+
if (isStealth) {
|
|
1690
|
+
settings["biome.linter.configPath"] = ".config/biome.json";
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
if (formatter === "prettier") {
|
|
1694
|
+
settings["editor.defaultFormatter"] = "esbenp.prettier-vscode";
|
|
1695
|
+
if (isStealth) {
|
|
1696
|
+
settings["prettier.configPath"] = ".config/prettier.json";
|
|
1697
|
+
settings["prettier.ignorePath"] = ".config/prettierignore";
|
|
1698
|
+
}
|
|
1699
|
+
} else if (formatter === "oxfmt") {
|
|
1700
|
+
settings["editor.defaultFormatter"] = "oxc.oxc-vscode";
|
|
1701
|
+
Object.assign(settings, OXFMT_LANGUAGE_SETTINGS);
|
|
1702
|
+
if (isStealth) {
|
|
1703
|
+
settings["oxc.fmt.configPath"] = ".config/oxfmt.json";
|
|
1704
|
+
}
|
|
1705
|
+
} else if (formatter === "biome") {
|
|
1706
|
+
settings["biome.enabled"] = true;
|
|
1707
|
+
settings["eslint.enable"] = false;
|
|
1708
|
+
settings["oxc.enable"] = false;
|
|
1709
|
+
settings["editor.defaultFormatter"] = "biomejs.biome";
|
|
1710
|
+
if (isStealth) {
|
|
1711
|
+
settings["biome.linter.configPath"] = ".config/biome.json";
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
return settings;
|
|
1715
|
+
}
|
|
1716
|
+
function renderVscodeFiles$1(params) {
|
|
1717
|
+
const { codeSnippets = {}, vscodeSettings = {} } = params;
|
|
1289
1718
|
const files = {};
|
|
1290
|
-
|
|
1291
|
-
|
|
1719
|
+
const recommendations = [
|
|
1720
|
+
...codeSnippets["vscode-extension-suggestion"] ?? [],
|
|
1721
|
+
...resolveVscodeRecommendations(params.linter, params.formatter)
|
|
1722
|
+
];
|
|
1723
|
+
if (recommendations.length > 0) {
|
|
1724
|
+
const uniqueRecommendations = [...new Set(recommendations)];
|
|
1292
1725
|
files[".vscode/extensions.json"] = {
|
|
1293
1726
|
type: "text",
|
|
1294
1727
|
content: JSON.stringify(
|
|
@@ -1300,9 +1733,13 @@ function generateVscodeFiles$1(params) {
|
|
|
1300
1733
|
)
|
|
1301
1734
|
};
|
|
1302
1735
|
}
|
|
1303
|
-
|
|
1736
|
+
const resolvedSettings = {
|
|
1737
|
+
...resolveVscodeSettings(params),
|
|
1738
|
+
...vscodeSettings
|
|
1739
|
+
};
|
|
1740
|
+
if (Object.keys(resolvedSettings).length > 0) {
|
|
1304
1741
|
const sortedSettings = Object.fromEntries(
|
|
1305
|
-
Object.entries(
|
|
1742
|
+
Object.entries(resolvedSettings).sort(([a], [b]) => a.localeCompare(b))
|
|
1306
1743
|
);
|
|
1307
1744
|
files[".vscode/settings.json"] = {
|
|
1308
1745
|
type: "text",
|
|
@@ -1346,7 +1783,7 @@ ${spaces}}`;
|
|
|
1346
1783
|
}
|
|
1347
1784
|
return String(value);
|
|
1348
1785
|
}
|
|
1349
|
-
function
|
|
1786
|
+
function renderViteConfig(params) {
|
|
1350
1787
|
const { viteConfig, codeSnippets } = params;
|
|
1351
1788
|
const configBody = formatValue(viteConfig, 0);
|
|
1352
1789
|
const viteConfigContent = [
|
|
@@ -1359,7 +1796,93 @@ function generateViteConfig(params) {
|
|
|
1359
1796
|
return { type: "text", content: viteConfigContent };
|
|
1360
1797
|
}
|
|
1361
1798
|
|
|
1362
|
-
function
|
|
1799
|
+
function toPrettierConfig(config = defaultFormatterMetaConfig) {
|
|
1800
|
+
return {
|
|
1801
|
+
$schema: "https://json.schemastore.org/prettierrc",
|
|
1802
|
+
printWidth: config.printWidth,
|
|
1803
|
+
tabWidth: config.tabWidth,
|
|
1804
|
+
useTabs: config.useTabs,
|
|
1805
|
+
semi: config.semi,
|
|
1806
|
+
singleQuote: config.singleQuote,
|
|
1807
|
+
trailingComma: config.trailingComma,
|
|
1808
|
+
bracketSpacing: config.bracketSpacing,
|
|
1809
|
+
arrowParens: config.arrowParens,
|
|
1810
|
+
overrides: [
|
|
1811
|
+
{
|
|
1812
|
+
files: ["*.md", "**/*.md"],
|
|
1813
|
+
options: { semi: false }
|
|
1814
|
+
},
|
|
1815
|
+
{
|
|
1816
|
+
files: ["*.yml", "*.yaml", "**/*.yml", "**/*.yaml"],
|
|
1817
|
+
options: { semi: false }
|
|
1818
|
+
}
|
|
1819
|
+
]
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
1822
|
+
function toPrettierIgnoreContent(config = defaultFormatterMetaConfig) {
|
|
1823
|
+
return config.ignorePatterns.join("\n");
|
|
1824
|
+
}
|
|
1825
|
+
function toOxfmtConfig(config = defaultFormatterMetaConfig) {
|
|
1826
|
+
return {
|
|
1827
|
+
printWidth: config.printWidth,
|
|
1828
|
+
tabWidth: config.tabWidth,
|
|
1829
|
+
useTabs: config.useTabs,
|
|
1830
|
+
semi: config.semi,
|
|
1831
|
+
singleQuote: config.singleQuote,
|
|
1832
|
+
trailingComma: config.trailingComma,
|
|
1833
|
+
bracketSpacing: config.bracketSpacing,
|
|
1834
|
+
arrowParens: config.arrowParens,
|
|
1835
|
+
ignorePatterns: config.ignorePatterns
|
|
1836
|
+
};
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
const defaultLinterMetaConfig = {
|
|
1840
|
+
ignorePatterns: ["dist"],
|
|
1841
|
+
rules: {
|
|
1842
|
+
noUnusedVars: {
|
|
1843
|
+
level: "warn",
|
|
1844
|
+
argsIgnorePattern: "^_",
|
|
1845
|
+
varsIgnorePattern: "^_",
|
|
1846
|
+
caughtErrorsIgnorePattern: "^_"
|
|
1847
|
+
},
|
|
1848
|
+
noUnusedExpressions: {
|
|
1849
|
+
level: "warn",
|
|
1850
|
+
allowShortCircuit: true
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
};
|
|
1854
|
+
|
|
1855
|
+
function renderOxlintConfig(params) {
|
|
1856
|
+
const config = params.config ?? defaultLinterMetaConfig;
|
|
1857
|
+
const { rules } = config;
|
|
1858
|
+
const plugins = ["unicorn", "typescript", "oxc"];
|
|
1859
|
+
if (params.react === true) {
|
|
1860
|
+
plugins.push("react");
|
|
1861
|
+
}
|
|
1862
|
+
return {
|
|
1863
|
+
$schema: params.schemaPath,
|
|
1864
|
+
plugins,
|
|
1865
|
+
...params.typescript === true ? { options: { typeAware: true } } : {},
|
|
1866
|
+
rules: {
|
|
1867
|
+
"no-unused-vars": [
|
|
1868
|
+
rules.noUnusedVars.level,
|
|
1869
|
+
{
|
|
1870
|
+
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
1871
|
+
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
1872
|
+
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
1873
|
+
}
|
|
1874
|
+
],
|
|
1875
|
+
"no-useless-escape": "off",
|
|
1876
|
+
"no-unused-expressions": [
|
|
1877
|
+
rules.noUnusedExpressions.level,
|
|
1878
|
+
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
1879
|
+
]
|
|
1880
|
+
},
|
|
1881
|
+
ignorePatterns: config.ignorePatterns
|
|
1882
|
+
};
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
function renderTypescriptConfigPackage(files) {
|
|
1363
1886
|
const basePath = ".config/typescript";
|
|
1364
1887
|
files[`${basePath}/package.json`] = {
|
|
1365
1888
|
type: "text",
|
|
@@ -1464,9 +1987,8 @@ In your package's \`tsconfig.json\`:
|
|
|
1464
1987
|
)
|
|
1465
1988
|
};
|
|
1466
1989
|
}
|
|
1467
|
-
function
|
|
1990
|
+
function renderOxlintConfigPackage(files) {
|
|
1468
1991
|
const basePath = ".config/oxlint";
|
|
1469
|
-
const { rules } = defaultLinterConfig;
|
|
1470
1992
|
files[`${basePath}/package.json`] = {
|
|
1471
1993
|
type: "text",
|
|
1472
1994
|
content: JSON.stringify(
|
|
@@ -1503,26 +2025,10 @@ oxlint -c node_modules/@config/oxlint/base.json
|
|
|
1503
2025
|
files[`${basePath}/base.json`] = {
|
|
1504
2026
|
type: "text",
|
|
1505
2027
|
content: JSON.stringify(
|
|
1506
|
-
{
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
"no-unused-vars": [
|
|
1511
|
-
rules.noUnusedVars.level,
|
|
1512
|
-
{
|
|
1513
|
-
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
1514
|
-
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
1515
|
-
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
1516
|
-
}
|
|
1517
|
-
],
|
|
1518
|
-
"no-useless-escape": "off",
|
|
1519
|
-
"no-unused-expressions": [
|
|
1520
|
-
rules.noUnusedExpressions.level,
|
|
1521
|
-
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
1522
|
-
]
|
|
1523
|
-
},
|
|
1524
|
-
ignorePatterns: defaultLinterConfig.ignorePatterns
|
|
1525
|
-
},
|
|
2028
|
+
renderOxlintConfig({
|
|
2029
|
+
schemaPath: "./node_modules/oxlint/configuration_schema.json",
|
|
2030
|
+
typescript: true
|
|
2031
|
+
}),
|
|
1526
2032
|
null,
|
|
1527
2033
|
2
|
|
1528
2034
|
)
|
|
@@ -1530,32 +2036,17 @@ oxlint -c node_modules/@config/oxlint/base.json
|
|
|
1530
2036
|
files[`${basePath}/react.json`] = {
|
|
1531
2037
|
type: "text",
|
|
1532
2038
|
content: JSON.stringify(
|
|
1533
|
-
{
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
rules.noUnusedVars.level,
|
|
1539
|
-
{
|
|
1540
|
-
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
1541
|
-
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
1542
|
-
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
1543
|
-
}
|
|
1544
|
-
],
|
|
1545
|
-
"no-useless-escape": "off",
|
|
1546
|
-
"no-unused-expressions": [
|
|
1547
|
-
rules.noUnusedExpressions.level,
|
|
1548
|
-
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
1549
|
-
]
|
|
1550
|
-
},
|
|
1551
|
-
ignorePatterns: defaultLinterConfig.ignorePatterns
|
|
1552
|
-
},
|
|
2039
|
+
renderOxlintConfig({
|
|
2040
|
+
schemaPath: "./node_modules/oxlint/configuration_schema.json",
|
|
2041
|
+
react: true,
|
|
2042
|
+
typescript: true
|
|
2043
|
+
}),
|
|
1553
2044
|
null,
|
|
1554
2045
|
2
|
|
1555
2046
|
)
|
|
1556
2047
|
};
|
|
1557
2048
|
}
|
|
1558
|
-
function
|
|
2049
|
+
function renderEslintConfigPackage(files) {
|
|
1559
2050
|
const basePath = ".config/eslint";
|
|
1560
2051
|
files[`${basePath}/package.json`] = {
|
|
1561
2052
|
type: "text",
|
|
@@ -1662,7 +2153,7 @@ export default tseslint.config(
|
|
|
1662
2153
|
`
|
|
1663
2154
|
};
|
|
1664
2155
|
}
|
|
1665
|
-
function
|
|
2156
|
+
function renderPrettierConfigPackage(files) {
|
|
1666
2157
|
const basePath = ".config/prettier";
|
|
1667
2158
|
files[`${basePath}/package.json`] = {
|
|
1668
2159
|
type: "text",
|
|
@@ -1675,7 +2166,7 @@ function generatePrettierConfigPackage(files) {
|
|
|
1675
2166
|
exports: {
|
|
1676
2167
|
".": "./base.json"
|
|
1677
2168
|
},
|
|
1678
|
-
files: ["base.json"]
|
|
2169
|
+
files: ["base.json", "prettierignore"]
|
|
1679
2170
|
},
|
|
1680
2171
|
null,
|
|
1681
2172
|
2
|
|
@@ -1710,10 +2201,14 @@ Or in \`.prettierrc.json\`:
|
|
|
1710
2201
|
};
|
|
1711
2202
|
files[`${basePath}/base.json`] = {
|
|
1712
2203
|
type: "text",
|
|
1713
|
-
content: JSON.stringify(
|
|
2204
|
+
content: JSON.stringify(toPrettierConfig(), null, 2)
|
|
2205
|
+
};
|
|
2206
|
+
files[`${basePath}/prettierignore`] = {
|
|
2207
|
+
type: "text",
|
|
2208
|
+
content: toPrettierIgnoreContent()
|
|
1714
2209
|
};
|
|
1715
2210
|
}
|
|
1716
|
-
function
|
|
2211
|
+
function renderOxfmtConfigPackage(files) {
|
|
1717
2212
|
const basePath = ".config/oxfmt";
|
|
1718
2213
|
files[`${basePath}/package.json`] = {
|
|
1719
2214
|
type: "text",
|
|
@@ -1749,11 +2244,11 @@ oxfmt -c node_modules/@config/oxfmt/base.json --write .
|
|
|
1749
2244
|
};
|
|
1750
2245
|
files[`${basePath}/base.json`] = {
|
|
1751
2246
|
type: "text",
|
|
1752
|
-
content: JSON.stringify(
|
|
2247
|
+
content: JSON.stringify(toOxfmtConfig(), null, 2)
|
|
1753
2248
|
};
|
|
1754
2249
|
}
|
|
1755
2250
|
|
|
1756
|
-
function
|
|
2251
|
+
function renderMonorepo(params) {
|
|
1757
2252
|
const {
|
|
1758
2253
|
name,
|
|
1759
2254
|
linter,
|
|
@@ -1762,19 +2257,20 @@ function generateMonorepo(params) {
|
|
|
1762
2257
|
pnpmManageVersions,
|
|
1763
2258
|
engine,
|
|
1764
2259
|
versions = {},
|
|
2260
|
+
ide = "vscode",
|
|
1765
2261
|
aiPlatforms
|
|
1766
2262
|
} = params;
|
|
1767
2263
|
const files = {};
|
|
1768
2264
|
const isPnpm = packageManager.name === "pnpm";
|
|
1769
2265
|
const devDependencies = {};
|
|
1770
2266
|
if (engine?.name === "node" && engine.version) {
|
|
1771
|
-
|
|
1772
|
-
devDependencies["@types/node"] = `^${majorVersion}.0.0`;
|
|
2267
|
+
devDependencies["@types/node"] = formatNodeTypesVersion(versions, engine);
|
|
1773
2268
|
} else {
|
|
1774
2269
|
devDependencies["@types/node"] = "^22.0.0";
|
|
1775
2270
|
}
|
|
1776
2271
|
if (linter === "oxlint") {
|
|
1777
2272
|
assignResolvedPackageVersion(devDependencies, versions, "oxlint");
|
|
2273
|
+
assignResolvedPackageVersion(devDependencies, versions, "oxlint-tsgolint");
|
|
1778
2274
|
} else if (linter === "eslint") {
|
|
1779
2275
|
assignResolvedPackageVersion(devDependencies, versions, "eslint");
|
|
1780
2276
|
} else if (linter === "biome") {
|
|
@@ -1790,13 +2286,7 @@ function generateMonorepo(params) {
|
|
|
1790
2286
|
version: "0.0.0",
|
|
1791
2287
|
private: true,
|
|
1792
2288
|
type: "module",
|
|
1793
|
-
scripts:
|
|
1794
|
-
dev: "pnpm --filter './apps/*' run dev",
|
|
1795
|
-
build: "pnpm --filter './packages/*' run build && pnpm --filter './apps/*' run build",
|
|
1796
|
-
test: "pnpm -r run test",
|
|
1797
|
-
lint: linter === "oxlint" ? "oxlint ." : linter === "biome" ? "biome check ." : "eslint .",
|
|
1798
|
-
format: formatter === "oxfmt" ? "oxfmt -c .config/oxfmt/base.json ." : formatter === "biome" ? "biome format . --write" : "prettier --config .config/prettier/base.json --write ."
|
|
1799
|
-
},
|
|
2289
|
+
scripts: packageJsonScripts.monorepoRoot(linter, formatter),
|
|
1800
2290
|
devDependencies
|
|
1801
2291
|
};
|
|
1802
2292
|
const engines = {};
|
|
@@ -1842,9 +2332,9 @@ function generateMonorepo(params) {
|
|
|
1842
2332
|
2
|
|
1843
2333
|
)
|
|
1844
2334
|
};
|
|
1845
|
-
|
|
2335
|
+
renderTypescriptConfigPackage(files);
|
|
1846
2336
|
if (linter === "oxlint") {
|
|
1847
|
-
|
|
2337
|
+
renderOxlintConfigPackage(files);
|
|
1848
2338
|
files["oxlint.json"] = {
|
|
1849
2339
|
type: "text",
|
|
1850
2340
|
content: JSON.stringify(
|
|
@@ -1857,7 +2347,7 @@ function generateMonorepo(params) {
|
|
|
1857
2347
|
)
|
|
1858
2348
|
};
|
|
1859
2349
|
} else if (linter === "eslint") {
|
|
1860
|
-
|
|
2350
|
+
renderEslintConfigPackage(files);
|
|
1861
2351
|
files["eslint.config.js"] = {
|
|
1862
2352
|
type: "text",
|
|
1863
2353
|
content: `import base from "@config/eslint/base";
|
|
@@ -1890,11 +2380,12 @@ export default [...base];
|
|
|
1890
2380
|
};
|
|
1891
2381
|
}
|
|
1892
2382
|
if (formatter === "oxfmt") {
|
|
1893
|
-
|
|
2383
|
+
renderOxfmtConfigPackage(files);
|
|
1894
2384
|
} else if (formatter === "prettier") {
|
|
1895
|
-
|
|
2385
|
+
renderPrettierConfigPackage(files);
|
|
1896
2386
|
}
|
|
1897
|
-
files[".
|
|
2387
|
+
files[".editorconfig"] = renderEditorConfig();
|
|
2388
|
+
files[".gitignore"] = renderGitignore("workspace-root");
|
|
1898
2389
|
files[".gitattributes"] = {
|
|
1899
2390
|
type: "text",
|
|
1900
2391
|
content: `* text=auto eol=lf
|
|
@@ -1902,7 +2393,9 @@ export default [...base];
|
|
|
1902
2393
|
*.{bat,[bB][aA][tT]} text eol=crlf
|
|
1903
2394
|
`
|
|
1904
2395
|
};
|
|
1905
|
-
|
|
2396
|
+
if (ide === "vscode") {
|
|
2397
|
+
renderVscodeFiles(files, linter, formatter, packageManager.name);
|
|
2398
|
+
}
|
|
1906
2399
|
files["README.md"] = {
|
|
1907
2400
|
type: "text",
|
|
1908
2401
|
content: `# ${name}
|
|
@@ -1930,104 +2423,50 @@ To add a new package to this workspace, run create-krispya from this directory a
|
|
|
1930
2423
|
`
|
|
1931
2424
|
};
|
|
1932
2425
|
if (aiPlatforms && aiPlatforms.length > 0) {
|
|
1933
|
-
|
|
2426
|
+
renderAiFiles(files, {
|
|
1934
2427
|
name,
|
|
1935
2428
|
packageManager: packageManager.name,
|
|
1936
2429
|
linter,
|
|
1937
2430
|
formatter,
|
|
1938
2431
|
isMonorepo: true,
|
|
2432
|
+
hasTypecheck: false,
|
|
1939
2433
|
platforms: aiPlatforms
|
|
1940
2434
|
});
|
|
1941
2435
|
}
|
|
1942
2436
|
return { files };
|
|
1943
2437
|
}
|
|
1944
|
-
function
|
|
1945
|
-
const recommendations = [];
|
|
1946
|
-
const settings = {};
|
|
1947
|
-
if (linter === "oxlint") {
|
|
1948
|
-
recommendations.push("oxc.oxc-vscode");
|
|
1949
|
-
settings["oxc.enable"] = true;
|
|
1950
|
-
settings["eslint.enable"] = false;
|
|
1951
|
-
settings["biome.enabled"] = false;
|
|
1952
|
-
} else if (linter === "eslint") {
|
|
1953
|
-
recommendations.push("dbaeumer.vscode-eslint");
|
|
1954
|
-
settings["eslint.enable"] = true;
|
|
1955
|
-
settings["oxc.enable"] = false;
|
|
1956
|
-
settings["biome.enabled"] = false;
|
|
1957
|
-
} else if (linter === "biome") {
|
|
1958
|
-
recommendations.push("biomejs.biome");
|
|
1959
|
-
settings["biome.enabled"] = true;
|
|
1960
|
-
settings["eslint.enable"] = false;
|
|
1961
|
-
settings["oxc.enable"] = false;
|
|
1962
|
-
}
|
|
1963
|
-
if (formatter === "oxfmt") {
|
|
1964
|
-
if (!recommendations.includes("oxc.oxc-vscode")) {
|
|
1965
|
-
recommendations.push("oxc.oxc-vscode");
|
|
1966
|
-
}
|
|
1967
|
-
settings["editor.defaultFormatter"] = "oxc.oxc-vscode";
|
|
1968
|
-
settings["[json]"] = {
|
|
1969
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1970
|
-
};
|
|
1971
|
-
settings["[jsonc]"] = {
|
|
1972
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1973
|
-
};
|
|
1974
|
-
} else if (formatter === "prettier") {
|
|
1975
|
-
recommendations.push("esbenp.prettier-vscode");
|
|
1976
|
-
settings["editor.defaultFormatter"] = "esbenp.prettier-vscode";
|
|
1977
|
-
} else if (formatter === "biome") {
|
|
1978
|
-
if (!recommendations.includes("biomejs.biome")) {
|
|
1979
|
-
recommendations.push("biomejs.biome");
|
|
1980
|
-
}
|
|
1981
|
-
settings["editor.defaultFormatter"] = "biomejs.biome";
|
|
1982
|
-
}
|
|
1983
|
-
files[".vscode/extensions.json"] = {
|
|
1984
|
-
type: "text",
|
|
1985
|
-
content: JSON.stringify({ recommendations }, null, 2)
|
|
1986
|
-
};
|
|
1987
|
-
const codeSnippets = {};
|
|
1988
|
-
if (recommendations.length > 0) {
|
|
1989
|
-
codeSnippets["vscode-extension-suggestion"] = recommendations;
|
|
1990
|
-
}
|
|
2438
|
+
function renderVscodeFiles(files, linter, formatter, packageManager = "pnpm") {
|
|
1991
2439
|
Object.assign(
|
|
1992
2440
|
files,
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
2441
|
+
renderVscodeFiles$1({
|
|
2442
|
+
linter,
|
|
2443
|
+
formatter,
|
|
2444
|
+
isMonorepo: true,
|
|
2445
|
+
packageManager
|
|
1996
2446
|
})
|
|
1997
2447
|
);
|
|
1998
2448
|
}
|
|
1999
2449
|
|
|
2000
|
-
const monorepo = {
|
|
2001
|
-
__proto__: null,
|
|
2002
|
-
generateEslintConfigPackage: generateEslintConfigPackage,
|
|
2003
|
-
generateMonorepo: generateMonorepo,
|
|
2004
|
-
generateOxfmtConfigPackage: generateOxfmtConfigPackage,
|
|
2005
|
-
generateOxlintConfigPackage: generateOxlintConfigPackage,
|
|
2006
|
-
generatePrettierConfigPackage: generatePrettierConfigPackage,
|
|
2007
|
-
generateTypescriptConfigPackage: generateTypescriptConfigPackage,
|
|
2008
|
-
generateVscodeFiles: generateVscodeFiles
|
|
2009
|
-
};
|
|
2010
|
-
|
|
2011
2450
|
function toBiomeLevel(level) {
|
|
2012
2451
|
return level;
|
|
2013
2452
|
}
|
|
2014
|
-
function
|
|
2453
|
+
function planBiome(builder, options) {
|
|
2015
2454
|
if (options == null || !options.linter && !options.formatter) {
|
|
2016
2455
|
return;
|
|
2017
2456
|
}
|
|
2018
|
-
const version =
|
|
2019
|
-
|
|
2020
|
-
const { rules } = defaultLinterConfig;
|
|
2457
|
+
const version = builder.getVersion("@biomejs/biome");
|
|
2458
|
+
builder.addDevDependency("@biomejs/biome");
|
|
2021
2459
|
const biomeConfig = {
|
|
2022
2460
|
$schema: `https://biomejs.dev/schemas/${version}/schema.json`
|
|
2023
2461
|
};
|
|
2024
2462
|
if (options.linter) {
|
|
2463
|
+
const linterConfig = options.linter.config;
|
|
2025
2464
|
biomeConfig.linter = {
|
|
2026
2465
|
enabled: true,
|
|
2027
2466
|
rules: {
|
|
2028
2467
|
recommended: true,
|
|
2029
2468
|
correctness: {
|
|
2030
|
-
noUnusedVariables: toBiomeLevel(rules.noUnusedVars.level)
|
|
2469
|
+
noUnusedVariables: toBiomeLevel(linterConfig.rules.noUnusedVars.level)
|
|
2031
2470
|
}
|
|
2032
2471
|
}
|
|
2033
2472
|
};
|
|
@@ -2037,19 +2476,20 @@ function generateBiome(generator, options) {
|
|
|
2037
2476
|
};
|
|
2038
2477
|
}
|
|
2039
2478
|
if (options.formatter) {
|
|
2479
|
+
const formatterConfig = options.formatter.config;
|
|
2040
2480
|
biomeConfig.formatter = {
|
|
2041
2481
|
enabled: true,
|
|
2042
|
-
lineWidth:
|
|
2043
|
-
indentWidth:
|
|
2044
|
-
indentStyle: "space"
|
|
2482
|
+
lineWidth: formatterConfig.printWidth,
|
|
2483
|
+
indentWidth: formatterConfig.tabWidth,
|
|
2484
|
+
indentStyle: formatterConfig.useTabs ? "tab" : "space"
|
|
2045
2485
|
};
|
|
2046
2486
|
biomeConfig.javascript = {
|
|
2047
2487
|
formatter: {
|
|
2048
|
-
semicolons: "always" ,
|
|
2049
|
-
quoteStyle: "single" ,
|
|
2050
|
-
trailingCommas:
|
|
2051
|
-
bracketSpacing:
|
|
2052
|
-
arrowParentheses: "always"
|
|
2488
|
+
semicolons: formatterConfig.semi ? "always" : "asNeeded",
|
|
2489
|
+
quoteStyle: formatterConfig.singleQuote ? "single" : "double",
|
|
2490
|
+
trailingCommas: formatterConfig.trailingComma,
|
|
2491
|
+
bracketSpacing: formatterConfig.bracketSpacing,
|
|
2492
|
+
arrowParentheses: formatterConfig.arrowParens === "always" ? "always" : "asNeeded"
|
|
2053
2493
|
}
|
|
2054
2494
|
};
|
|
2055
2495
|
biomeConfig.json = {
|
|
@@ -2062,53 +2502,48 @@ function generateBiome(generator, options) {
|
|
|
2062
2502
|
enabled: false
|
|
2063
2503
|
};
|
|
2064
2504
|
}
|
|
2065
|
-
const isStealth =
|
|
2505
|
+
const isStealth = builder.isStealthConfig();
|
|
2066
2506
|
if (isStealth) {
|
|
2067
|
-
|
|
2507
|
+
builder.addFile(".config/biome.json", {
|
|
2068
2508
|
type: "text",
|
|
2069
2509
|
content: JSON.stringify(biomeConfig, null, 2)
|
|
2070
2510
|
});
|
|
2071
2511
|
if (options.linter) {
|
|
2072
|
-
|
|
2512
|
+
builder.addScripts(packageJsonScripts.lint.biome(".config"));
|
|
2073
2513
|
}
|
|
2074
2514
|
if (options.formatter) {
|
|
2075
|
-
|
|
2515
|
+
builder.addScripts(packageJsonScripts.format.biome(".config"));
|
|
2076
2516
|
}
|
|
2077
|
-
generator.addVscodeSetting("biome.linter.configPath", ".config/biome.json");
|
|
2078
2517
|
} else {
|
|
2079
|
-
|
|
2518
|
+
builder.addFile("biome.json", {
|
|
2080
2519
|
type: "text",
|
|
2081
2520
|
content: JSON.stringify(biomeConfig, null, 2)
|
|
2082
2521
|
});
|
|
2083
2522
|
if (options.linter) {
|
|
2084
|
-
|
|
2523
|
+
builder.addScripts(packageJsonScripts.lint.biome());
|
|
2085
2524
|
}
|
|
2086
2525
|
if (options.formatter) {
|
|
2087
|
-
|
|
2526
|
+
builder.addScripts(packageJsonScripts.format.biome());
|
|
2088
2527
|
}
|
|
2089
2528
|
}
|
|
2090
2529
|
const roles = [];
|
|
2091
2530
|
if (options.linter) roles.push("linter");
|
|
2092
2531
|
if (options.formatter) roles.push("formatter");
|
|
2093
|
-
|
|
2532
|
+
builder.inject(
|
|
2094
2533
|
"readme-tools",
|
|
2095
2534
|
`[Biome](https://biomejs.dev/) - Fast ${roles.join(" and ")} for JavaScript and TypeScript`
|
|
2096
2535
|
);
|
|
2097
|
-
|
|
2098
|
-
generator.addVscodeSetting("biome.enabled", true);
|
|
2099
|
-
if (options.formatter) {
|
|
2100
|
-
generator.addVscodeSetting("editor.defaultFormatter", "biomejs.biome");
|
|
2101
|
-
}
|
|
2536
|
+
builder.inject("vscode-extension-suggestion", "biomejs.biome");
|
|
2102
2537
|
}
|
|
2103
2538
|
|
|
2104
|
-
function
|
|
2539
|
+
function planDrei(builder, options) {
|
|
2105
2540
|
if (options == null) {
|
|
2106
2541
|
return;
|
|
2107
2542
|
}
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2543
|
+
builder.addDependency("@react-three/drei");
|
|
2544
|
+
builder.inject("import", `import { Environment } from "@react-three/drei"`);
|
|
2545
|
+
builder.inject("scene", '<Environment background preset="city" />');
|
|
2546
|
+
builder.inject(
|
|
2112
2547
|
"readme-libraries",
|
|
2113
2548
|
`[@react-three/drei](https://drei.docs.pmnd.rs/) - Useful helpers for @react-three/fiber`
|
|
2114
2549
|
);
|
|
@@ -2117,25 +2552,28 @@ function generateDrei(generator, options) {
|
|
|
2117
2552
|
function toEslintLevel(level) {
|
|
2118
2553
|
return level;
|
|
2119
2554
|
}
|
|
2120
|
-
function
|
|
2121
|
-
|
|
2122
|
-
|
|
2555
|
+
function planEslint(builder, options) {
|
|
2556
|
+
if (options == null) {
|
|
2557
|
+
return;
|
|
2558
|
+
}
|
|
2559
|
+
builder.addDevDependency("eslint");
|
|
2560
|
+
const template = builder.options.template ?? "vanilla";
|
|
2123
2561
|
const baseTemplate = getBaseTemplate(template);
|
|
2124
2562
|
const isTypescript = getLanguageFromTemplate(template) === "typescript";
|
|
2125
2563
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2126
|
-
const { rules } =
|
|
2564
|
+
const { rules } = options.config;
|
|
2127
2565
|
const imports = ['import js from "@eslint/js"'];
|
|
2128
2566
|
const configs = ["js.configs.recommended"];
|
|
2129
2567
|
if (isTypescript) {
|
|
2130
|
-
|
|
2568
|
+
builder.addDevDependency("typescript-eslint");
|
|
2131
2569
|
imports.push('import tseslint from "typescript-eslint"');
|
|
2132
2570
|
configs.push("...tseslint.configs.recommended");
|
|
2133
2571
|
}
|
|
2134
2572
|
if (isReact) {
|
|
2135
|
-
|
|
2573
|
+
builder.addDevDependency("eslint-plugin-react-hooks");
|
|
2136
2574
|
imports.push('import reactHooks from "eslint-plugin-react-hooks"');
|
|
2137
2575
|
}
|
|
2138
|
-
const ignoresArray = JSON.stringify(
|
|
2576
|
+
const ignoresArray = JSON.stringify(options.config.ignorePatterns);
|
|
2139
2577
|
const unusedVarsRule = isTypescript ? "@typescript-eslint/no-unused-vars" : "no-unused-vars";
|
|
2140
2578
|
const rulesConfig = {
|
|
2141
2579
|
[unusedVarsRule]: [
|
|
@@ -2169,34 +2607,30 @@ function generateEslint(generator, options) {
|
|
|
2169
2607
|
},`,
|
|
2170
2608
|
"]"
|
|
2171
2609
|
].filter(Boolean).join("\n");
|
|
2172
|
-
const isStealth =
|
|
2610
|
+
const isStealth = builder.isStealthConfig();
|
|
2173
2611
|
if (isStealth) {
|
|
2174
|
-
|
|
2612
|
+
builder.addFile(".config/eslint.config.js", {
|
|
2175
2613
|
type: "text",
|
|
2176
2614
|
content: configContent
|
|
2177
2615
|
});
|
|
2178
|
-
|
|
2179
|
-
generator.addVscodeSetting("eslint.options", {
|
|
2180
|
-
overrideConfigFile: ".config/eslint.config.js"
|
|
2181
|
-
});
|
|
2616
|
+
builder.addScripts(packageJsonScripts.lint.eslint(".config/eslint.config.js"));
|
|
2182
2617
|
} else {
|
|
2183
|
-
|
|
2618
|
+
builder.addFile("eslint.config.js", {
|
|
2184
2619
|
type: "text",
|
|
2185
2620
|
content: configContent
|
|
2186
2621
|
});
|
|
2187
|
-
|
|
2622
|
+
builder.addScripts(packageJsonScripts.lint.eslint());
|
|
2188
2623
|
}
|
|
2189
|
-
|
|
2624
|
+
builder.inject(
|
|
2190
2625
|
"readme-tools",
|
|
2191
2626
|
"[ESLint](https://eslint.org/) - Linter for JavaScript and TypeScript"
|
|
2192
2627
|
);
|
|
2193
|
-
|
|
2194
|
-
generator.addVscodeSetting("eslint.enable", true);
|
|
2628
|
+
builder.inject("vscode-extension-suggestion", "dbaeumer.vscode-eslint");
|
|
2195
2629
|
}
|
|
2196
2630
|
|
|
2197
|
-
function
|
|
2198
|
-
|
|
2199
|
-
|
|
2631
|
+
function planFiber(builder, _options) {
|
|
2632
|
+
builder.inject("import", `import { Box } from "./box.js"`);
|
|
2633
|
+
builder.inject(
|
|
2200
2634
|
"scene",
|
|
2201
2635
|
[
|
|
2202
2636
|
`<ambientLight intensity={Math.PI / 2} />`,
|
|
@@ -2206,7 +2640,7 @@ function generateFiber(generator, _options) {
|
|
|
2206
2640
|
`<Box position={[1.2, 0, 0]} />`
|
|
2207
2641
|
].join("\n")
|
|
2208
2642
|
);
|
|
2209
|
-
|
|
2643
|
+
builder.addFile("src/box.tsx", {
|
|
2210
2644
|
type: "text",
|
|
2211
2645
|
content: `import type { Mesh } from 'three'
|
|
2212
2646
|
import { useRef, useState } from 'react'
|
|
@@ -2233,11 +2667,11 @@ export function Box(props: ThreeElements['mesh']) {
|
|
|
2233
2667
|
});
|
|
2234
2668
|
}
|
|
2235
2669
|
|
|
2236
|
-
function
|
|
2237
|
-
if (options === false || getPackageManagerName(
|
|
2670
|
+
function planGithubPages(builder, options) {
|
|
2671
|
+
if (options === false || getPackageManagerName(builder.options.packageManager) !== "npm") {
|
|
2238
2672
|
return;
|
|
2239
2673
|
}
|
|
2240
|
-
|
|
2674
|
+
builder.addFile(".github/workflows/gh-pages.yml", {
|
|
2241
2675
|
type: "text",
|
|
2242
2676
|
content: `name: Deploy to Github Pages
|
|
2243
2677
|
|
|
@@ -2283,10 +2717,10 @@ jobs:
|
|
|
2283
2717
|
uses: actions/deploy-pages@v4
|
|
2284
2718
|
`
|
|
2285
2719
|
});
|
|
2286
|
-
|
|
2287
|
-
if (
|
|
2288
|
-
const address = `${
|
|
2289
|
-
|
|
2720
|
+
builder.inject("readme-start", `A github pages deployment action is configurd.`);
|
|
2721
|
+
if (builder.options.githubUserName != null && builder.options.githubRepoName != null) {
|
|
2722
|
+
const address = `${builder.options.githubUserName}.github.io/${builder.options.githubRepoName}`;
|
|
2723
|
+
builder.inject(
|
|
2290
2724
|
"readme-start",
|
|
2291
2725
|
`Your app will be publish at [${address}](https://${address}) once the github action is finished.
|
|
2292
2726
|
`
|
|
@@ -2294,228 +2728,199 @@ jobs:
|
|
|
2294
2728
|
}
|
|
2295
2729
|
}
|
|
2296
2730
|
|
|
2297
|
-
function
|
|
2731
|
+
function planHandle(builder, options) {
|
|
2298
2732
|
if (options == null) {
|
|
2299
2733
|
return;
|
|
2300
2734
|
}
|
|
2301
|
-
|
|
2302
|
-
|
|
2735
|
+
builder.addDependency("@react-three/handle");
|
|
2736
|
+
builder.inject(
|
|
2303
2737
|
"readme-libraries",
|
|
2304
2738
|
`[@react-three/handle](https://pmndrs.github.io/xr/docs/handles/introduction) - interactive controls and handles for your 3D objects`
|
|
2305
2739
|
);
|
|
2306
2740
|
}
|
|
2307
2741
|
|
|
2308
|
-
function
|
|
2742
|
+
function planKoota(builder, options) {
|
|
2309
2743
|
if (options == null) {
|
|
2310
2744
|
return;
|
|
2311
2745
|
}
|
|
2312
|
-
|
|
2313
|
-
|
|
2746
|
+
builder.addDependency("koota");
|
|
2747
|
+
builder.inject(
|
|
2314
2748
|
"readme-libraries",
|
|
2315
2749
|
`[koota](https://github.com/pmndrs/koota) - ECS-based state management library optimized for real-time apps, games, and XR experiences`
|
|
2316
2750
|
);
|
|
2317
2751
|
}
|
|
2318
2752
|
|
|
2319
|
-
function
|
|
2753
|
+
function planLeva(builder, options) {
|
|
2320
2754
|
if (options == null) {
|
|
2321
2755
|
return;
|
|
2322
2756
|
}
|
|
2323
|
-
|
|
2324
|
-
|
|
2757
|
+
builder.addDependency("leva");
|
|
2758
|
+
builder.inject(
|
|
2325
2759
|
"readme-libraries",
|
|
2326
2760
|
`[leva](https://github.com/pmndrs/leva) - HTML GUI panel for React with lightweight, beautiful and extensible controls`
|
|
2327
2761
|
);
|
|
2328
2762
|
}
|
|
2329
2763
|
|
|
2330
|
-
function
|
|
2764
|
+
function planOffscreen(builder, options) {
|
|
2331
2765
|
if (options == null) {
|
|
2332
2766
|
return;
|
|
2333
2767
|
}
|
|
2334
|
-
if (
|
|
2768
|
+
if (builder.options.xr != null) {
|
|
2335
2769
|
console.info(
|
|
2336
2770
|
color__default.blue("Info:"),
|
|
2337
2771
|
"@react-three/offscreen is disabled because it is not supported with XR"
|
|
2338
2772
|
);
|
|
2339
2773
|
return;
|
|
2340
2774
|
}
|
|
2341
|
-
|
|
2342
|
-
|
|
2775
|
+
builder.addDependency("@react-three/offscreen");
|
|
2776
|
+
builder.inject(
|
|
2343
2777
|
"readme-libraries",
|
|
2344
2778
|
`[@react-three/offscreen](https://github.com/pmndrs/offscreen) - Offload your scene to a worker thread for better performance`
|
|
2345
2779
|
);
|
|
2346
2780
|
}
|
|
2347
2781
|
|
|
2348
|
-
function
|
|
2349
|
-
|
|
2782
|
+
function planOxfmt(builder, options) {
|
|
2783
|
+
if (options == null) {
|
|
2784
|
+
return;
|
|
2785
|
+
}
|
|
2786
|
+
const isMonorepo = builder.options.workspaceRoot != null;
|
|
2350
2787
|
if (isMonorepo) {
|
|
2351
|
-
|
|
2788
|
+
builder.addDevDependency("@config/oxfmt", { version: "workspace:*" });
|
|
2352
2789
|
const configPath = "node_modules/@config/oxfmt/base.json";
|
|
2353
|
-
|
|
2354
|
-
generator.addVscodeSetting("oxc.fmt.configPath", configPath);
|
|
2790
|
+
builder.addScripts(packageJsonScripts.format.oxfmt(configPath));
|
|
2355
2791
|
} else {
|
|
2356
|
-
|
|
2357
|
-
const isStealth =
|
|
2792
|
+
builder.addDevDependency("oxfmt");
|
|
2793
|
+
const isStealth = builder.isStealthConfig();
|
|
2358
2794
|
if (isStealth) {
|
|
2359
|
-
|
|
2795
|
+
builder.addFile(".config/oxfmt.json", {
|
|
2360
2796
|
type: "text",
|
|
2361
|
-
content: JSON.stringify(
|
|
2797
|
+
content: JSON.stringify(toOxfmtConfig(options.config), null, 2)
|
|
2362
2798
|
});
|
|
2363
|
-
|
|
2364
|
-
generator.addVscodeSetting("oxc.fmt.configPath", ".config/oxfmt.json");
|
|
2799
|
+
builder.addScripts(packageJsonScripts.format.oxfmt(".config/oxfmt.json"));
|
|
2365
2800
|
} else {
|
|
2366
|
-
|
|
2801
|
+
builder.addFile("oxfmt.json", {
|
|
2367
2802
|
type: "text",
|
|
2368
|
-
content: JSON.stringify(
|
|
2803
|
+
content: JSON.stringify(toOxfmtConfig(options.config), null, 2)
|
|
2369
2804
|
});
|
|
2370
|
-
|
|
2805
|
+
builder.addScripts(packageJsonScripts.format.oxfmt("oxfmt.json"));
|
|
2371
2806
|
}
|
|
2372
2807
|
}
|
|
2373
|
-
|
|
2808
|
+
builder.inject(
|
|
2374
2809
|
"readme-tools",
|
|
2375
2810
|
"[Oxfmt](https://oxc.rs/docs/guide/usage/formatter) - Fast Prettier-compatible code formatter"
|
|
2376
2811
|
);
|
|
2377
|
-
|
|
2378
|
-
generator.addVscodeSetting("editor.defaultFormatter", "oxc.oxc-vscode");
|
|
2379
|
-
generator.addVscodeSetting("[json]", {
|
|
2380
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
2381
|
-
});
|
|
2382
|
-
generator.addVscodeSetting("[jsonc]", {
|
|
2383
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
2384
|
-
});
|
|
2385
|
-
generator.addVscodeSetting("[markdown]", {
|
|
2386
|
-
"editor.defaultFormatter": "vscode.markdown-language-features"
|
|
2387
|
-
});
|
|
2388
|
-
generator.addVscodeSetting("[yaml]", {
|
|
2389
|
-
"editor.defaultFormatter": "redhat.vscode-yaml"
|
|
2390
|
-
});
|
|
2812
|
+
builder.inject("vscode-extension-suggestion", "oxc.oxc-vscode");
|
|
2391
2813
|
}
|
|
2392
2814
|
|
|
2393
|
-
function
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
const template =
|
|
2815
|
+
function planOxlint(builder, options) {
|
|
2816
|
+
if (options == null) {
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2819
|
+
const template = builder.options.template ?? "vanilla";
|
|
2398
2820
|
const baseTemplate = getBaseTemplate(template);
|
|
2821
|
+
const isTypescript = getLanguageFromTemplate(template) === "typescript";
|
|
2399
2822
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2400
|
-
const isMonorepo =
|
|
2823
|
+
const isMonorepo = builder.options.workspaceRoot != null;
|
|
2401
2824
|
if (isMonorepo) {
|
|
2402
|
-
|
|
2825
|
+
builder.addDevDependency("@config/oxlint", { version: "workspace:*" });
|
|
2403
2826
|
const configPath = isReact ? "node_modules/@config/oxlint/react.json" : "node_modules/@config/oxlint/base.json";
|
|
2404
|
-
|
|
2405
|
-
generator.addVscodeSetting("oxc.configPath", configPath);
|
|
2827
|
+
builder.addScripts(packageJsonScripts.lint.oxlint(configPath));
|
|
2406
2828
|
} else {
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
const plugins = ["unicorn", "typescript", "oxc"];
|
|
2411
|
-
if (isReact) {
|
|
2412
|
-
plugins.push("react");
|
|
2829
|
+
builder.addDevDependency("oxlint");
|
|
2830
|
+
if (isTypescript) {
|
|
2831
|
+
builder.addDevDependency("oxlint-tsgolint");
|
|
2413
2832
|
}
|
|
2414
|
-
const
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
2422
|
-
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
2423
|
-
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
2424
|
-
}
|
|
2425
|
-
],
|
|
2426
|
-
"no-useless-escape": "off",
|
|
2427
|
-
"no-unused-expressions": [
|
|
2428
|
-
toOxlintLevel(rules.noUnusedExpressions.level),
|
|
2429
|
-
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
2430
|
-
]
|
|
2431
|
-
},
|
|
2432
|
-
ignorePatterns: defaultLinterConfig.ignorePatterns
|
|
2433
|
-
};
|
|
2833
|
+
const isStealth = builder.isStealthConfig();
|
|
2834
|
+
const oxlintConfig = renderOxlintConfig({
|
|
2835
|
+
schemaPath: isStealth ? "../node_modules/oxlint/configuration_schema.json" : "./node_modules/oxlint/configuration_schema.json",
|
|
2836
|
+
react: isReact,
|
|
2837
|
+
typescript: isTypescript,
|
|
2838
|
+
config: options.config
|
|
2839
|
+
});
|
|
2434
2840
|
if (isStealth) {
|
|
2435
|
-
|
|
2841
|
+
builder.addFile(".config/oxlint.json", {
|
|
2436
2842
|
type: "text",
|
|
2437
2843
|
content: JSON.stringify(oxlintConfig, null, 2)
|
|
2438
2844
|
});
|
|
2439
|
-
|
|
2440
|
-
generator.addVscodeSetting("oxc.configPath", ".config/oxlint.json");
|
|
2845
|
+
builder.addScripts(packageJsonScripts.lint.oxlint(".config/oxlint.json"));
|
|
2441
2846
|
} else {
|
|
2442
|
-
|
|
2847
|
+
builder.addFile("oxlint.json", {
|
|
2443
2848
|
type: "text",
|
|
2444
2849
|
content: JSON.stringify(oxlintConfig, null, 2)
|
|
2445
2850
|
});
|
|
2446
|
-
|
|
2851
|
+
builder.addScripts(packageJsonScripts.lint.oxlint());
|
|
2447
2852
|
}
|
|
2448
2853
|
}
|
|
2449
|
-
|
|
2854
|
+
builder.inject(
|
|
2450
2855
|
"readme-tools",
|
|
2451
2856
|
"[Oxlint](https://oxc.rs/docs/guide/usage/linter) - A fast linter for JavaScript and TypeScript"
|
|
2452
2857
|
);
|
|
2453
|
-
|
|
2454
|
-
generator.addVscodeSetting("oxc.enable", true);
|
|
2858
|
+
builder.inject("vscode-extension-suggestion", "oxc.oxc-vscode");
|
|
2455
2859
|
}
|
|
2456
2860
|
|
|
2457
|
-
function
|
|
2861
|
+
function planPostprocessing(builder, options) {
|
|
2458
2862
|
if (options == null) {
|
|
2459
2863
|
return;
|
|
2460
2864
|
}
|
|
2461
|
-
if (
|
|
2865
|
+
if (builder.options.xr != null) {
|
|
2462
2866
|
console.info(
|
|
2463
2867
|
color__default.blue("Info:"),
|
|
2464
2868
|
"@react-three/postprocessing is disabled because it is not supported with XR"
|
|
2465
2869
|
);
|
|
2466
2870
|
return;
|
|
2467
2871
|
}
|
|
2468
|
-
|
|
2469
|
-
|
|
2872
|
+
builder.addDependency("@react-three/postprocessing");
|
|
2873
|
+
builder.inject(
|
|
2470
2874
|
"readme-libraries",
|
|
2471
2875
|
`[@react-three/postprocessing](https://react-postprocessing.docs.pmnd.rs/) - Post-processing effects for @react-three/fiber`
|
|
2472
2876
|
);
|
|
2473
2877
|
}
|
|
2474
2878
|
|
|
2475
|
-
function
|
|
2476
|
-
|
|
2477
|
-
|
|
2879
|
+
function planPrettier(builder, options) {
|
|
2880
|
+
if (options == null) {
|
|
2881
|
+
return;
|
|
2882
|
+
}
|
|
2883
|
+
builder.addDevDependency("prettier");
|
|
2884
|
+
const isStealth = builder.isStealthConfig();
|
|
2478
2885
|
if (isStealth) {
|
|
2479
|
-
|
|
2886
|
+
builder.addFile(".config/prettier.json", {
|
|
2887
|
+
type: "text",
|
|
2888
|
+
content: JSON.stringify(toPrettierConfig(options.config), null, 2)
|
|
2889
|
+
});
|
|
2890
|
+
builder.addFile(".config/prettierignore", {
|
|
2480
2891
|
type: "text",
|
|
2481
|
-
content:
|
|
2892
|
+
content: toPrettierIgnoreContent(options.config)
|
|
2482
2893
|
});
|
|
2483
|
-
|
|
2484
|
-
|
|
2894
|
+
builder.addScripts(
|
|
2895
|
+
packageJsonScripts.format.prettier(".config/prettier.json", ".config/prettierignore")
|
|
2896
|
+
);
|
|
2485
2897
|
} else {
|
|
2486
|
-
|
|
2898
|
+
builder.addFile(".prettierrc", {
|
|
2487
2899
|
type: "text",
|
|
2488
|
-
content: JSON.stringify(
|
|
2900
|
+
content: JSON.stringify(toPrettierConfig(options.config), null, 2)
|
|
2489
2901
|
});
|
|
2490
|
-
|
|
2902
|
+
builder.addFile(".prettierignore", {
|
|
2903
|
+
type: "text",
|
|
2904
|
+
content: toPrettierIgnoreContent(options.config)
|
|
2905
|
+
});
|
|
2906
|
+
builder.addScripts(packageJsonScripts.format.prettier());
|
|
2491
2907
|
}
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
generator.addVscodeSetting("editor.defaultFormatter", "esbenp.prettier-vscode");
|
|
2908
|
+
builder.inject("readme-tools", "[Prettier](https://prettier.io/) - Opinionated code formatter");
|
|
2909
|
+
builder.inject("vscode-extension-suggestion", "esbenp.prettier-vscode");
|
|
2495
2910
|
}
|
|
2496
2911
|
|
|
2497
|
-
function
|
|
2912
|
+
function planRapier(builder, options) {
|
|
2498
2913
|
if (options == null) {
|
|
2499
2914
|
return;
|
|
2500
2915
|
}
|
|
2501
|
-
|
|
2502
|
-
|
|
2916
|
+
builder.addDependency("@react-three/rapier");
|
|
2917
|
+
builder.inject(
|
|
2503
2918
|
"readme-libraries",
|
|
2504
2919
|
`[@react-three/rapier](https://github.com/pmndrs/react-three-rapier) - Physics based on Rapier for your @react-three/fiber scene`
|
|
2505
2920
|
);
|
|
2506
2921
|
}
|
|
2507
2922
|
|
|
2508
|
-
function
|
|
2509
|
-
const set = /* @__PURE__ */ new Set();
|
|
2510
|
-
for (const arr of array) {
|
|
2511
|
-
for (const item of arr) {
|
|
2512
|
-
set.add(item);
|
|
2513
|
-
}
|
|
2514
|
-
}
|
|
2515
|
-
return Array.from(set);
|
|
2516
|
-
}
|
|
2517
|
-
|
|
2518
|
-
function generateProvidersModule(generator) {
|
|
2923
|
+
function generateProvidersModule(builder) {
|
|
2519
2924
|
const canvasProviders = [];
|
|
2520
2925
|
const globalProviders = [];
|
|
2521
2926
|
const providerDefs = {
|
|
@@ -2581,13 +2986,13 @@ function generateProvidersModule(generator) {
|
|
|
2581
2986
|
]
|
|
2582
2987
|
}
|
|
2583
2988
|
};
|
|
2584
|
-
if (
|
|
2989
|
+
if (builder.options.rapier) {
|
|
2585
2990
|
canvasProviders.push("rapier");
|
|
2586
2991
|
}
|
|
2587
|
-
if (!!
|
|
2992
|
+
if (!!builder.options.postprocessing && !builder.options.xr) {
|
|
2588
2993
|
canvasProviders.push("postprocessing");
|
|
2589
2994
|
}
|
|
2590
|
-
if (
|
|
2995
|
+
if (builder.options.uikit) {
|
|
2591
2996
|
globalProviders.push("uikit");
|
|
2592
2997
|
}
|
|
2593
2998
|
function generateProviderFunction(name, { jsdoc, providers }) {
|
|
@@ -2650,20 +3055,20 @@ ${jsdoc.split("\n").map((line) => ` * ${line}`).join("\n")}
|
|
|
2650
3055
|
${canvas.code}
|
|
2651
3056
|
`;
|
|
2652
3057
|
}
|
|
2653
|
-
function
|
|
3058
|
+
function planTriplex(builder, options) {
|
|
2654
3059
|
if (options == null) {
|
|
2655
3060
|
return;
|
|
2656
3061
|
}
|
|
2657
|
-
|
|
2658
|
-
|
|
3062
|
+
builder.inject("vscode-extension-suggestion", "trytriplex.triplex-vsce");
|
|
3063
|
+
builder.inject(
|
|
2659
3064
|
"readme-tools",
|
|
2660
3065
|
`[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).`
|
|
2661
3066
|
);
|
|
2662
|
-
|
|
2663
|
-
content: generateProvidersModule(
|
|
3067
|
+
builder.addFile(".triplex/providers.tsx", {
|
|
3068
|
+
content: generateProvidersModule(builder),
|
|
2664
3069
|
type: "text"
|
|
2665
3070
|
});
|
|
2666
|
-
|
|
3071
|
+
builder.addFile(".triplex/config.json", {
|
|
2667
3072
|
content: JSON.stringify(
|
|
2668
3073
|
{
|
|
2669
3074
|
$schema: "https://triplex.dev/config.schema.json",
|
|
@@ -2676,9 +3081,9 @@ function generateTriplex(generator, options) {
|
|
|
2676
3081
|
});
|
|
2677
3082
|
}
|
|
2678
3083
|
|
|
2679
|
-
function
|
|
2680
|
-
|
|
2681
|
-
const template =
|
|
3084
|
+
function planTsdown(builder) {
|
|
3085
|
+
builder.addDevDependency("tsdown");
|
|
3086
|
+
const template = builder.options.template ?? "vanilla";
|
|
2682
3087
|
const baseTemplate = getBaseTemplate(template);
|
|
2683
3088
|
const language = getLanguageFromTemplate(template);
|
|
2684
3089
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
@@ -2698,36 +3103,36 @@ function generateTsdown(generator) {
|
|
|
2698
3103
|
configLines.push(` },`);
|
|
2699
3104
|
}
|
|
2700
3105
|
configLines.push(`})`);
|
|
2701
|
-
|
|
3106
|
+
builder.addFile(`tsdown.config.${ext}`, {
|
|
2702
3107
|
type: "text",
|
|
2703
3108
|
content: configLines.join("\n")
|
|
2704
3109
|
});
|
|
2705
|
-
|
|
2706
|
-
|
|
3110
|
+
builder.addScripts(packageJsonScripts.build.tsdown);
|
|
3111
|
+
builder.inject(
|
|
2707
3112
|
"readme-libraries",
|
|
2708
3113
|
"[tsdown](https://github.com/nicepkg/tsdown) - Fast TypeScript bundler powered by esbuild"
|
|
2709
3114
|
);
|
|
2710
3115
|
}
|
|
2711
3116
|
|
|
2712
|
-
function
|
|
3117
|
+
function planUikit(builder, options) {
|
|
2713
3118
|
if (options == null) {
|
|
2714
3119
|
return;
|
|
2715
3120
|
}
|
|
2716
|
-
|
|
2717
|
-
|
|
3121
|
+
builder.addDependency("@react-three/uikit");
|
|
3122
|
+
builder.inject(
|
|
2718
3123
|
"readme-libraries",
|
|
2719
3124
|
`[@react-three/uikit](https://pmndrs.github.io/uikit/docs/) - UI primitives for React Three Fiber`
|
|
2720
3125
|
);
|
|
2721
3126
|
}
|
|
2722
3127
|
|
|
2723
|
-
function
|
|
2724
|
-
|
|
2725
|
-
const template =
|
|
3128
|
+
function planUnbuild(builder) {
|
|
3129
|
+
builder.addDevDependency("unbuild");
|
|
3130
|
+
const template = builder.options.template ?? "vanilla";
|
|
2726
3131
|
const baseTemplate = getBaseTemplate(template);
|
|
2727
3132
|
const language = getLanguageFromTemplate(template);
|
|
2728
3133
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2729
3134
|
const ext = language === "typescript" ? "ts" : "js";
|
|
2730
|
-
const isMonorepo =
|
|
3135
|
+
const isMonorepo = builder.options.workspaceRoot != null;
|
|
2731
3136
|
const buildConfigLines = [
|
|
2732
3137
|
`import { defineBuildConfig } from "unbuild"`,
|
|
2733
3138
|
``,
|
|
@@ -2745,51 +3150,54 @@ function generateUnbuild(generator) {
|
|
|
2745
3150
|
}
|
|
2746
3151
|
buildConfigLines.push(` },`);
|
|
2747
3152
|
buildConfigLines.push(`})`);
|
|
2748
|
-
const isStealth =
|
|
3153
|
+
const isStealth = builder.isStealthConfig() && !isMonorepo;
|
|
2749
3154
|
if (isStealth) {
|
|
2750
|
-
|
|
3155
|
+
builder.addFile(`.config/build.config.${ext}`, {
|
|
2751
3156
|
type: "text",
|
|
2752
3157
|
content: buildConfigLines.join("\n")
|
|
2753
3158
|
});
|
|
2754
|
-
|
|
3159
|
+
builder.addScripts(packageJsonScripts.build.unbuild(`.config/build.config.${ext}`));
|
|
2755
3160
|
} else {
|
|
2756
|
-
|
|
3161
|
+
builder.addFile(`build.config.${ext}`, {
|
|
2757
3162
|
type: "text",
|
|
2758
3163
|
content: buildConfigLines.join("\n")
|
|
2759
3164
|
});
|
|
2760
|
-
|
|
3165
|
+
builder.addScripts(packageJsonScripts.build.unbuild());
|
|
2761
3166
|
}
|
|
2762
|
-
|
|
3167
|
+
builder.inject(
|
|
2763
3168
|
"readme-libraries",
|
|
2764
3169
|
"[unbuild](https://github.com/unjs/unbuild) - Unified JavaScript build system"
|
|
2765
3170
|
);
|
|
2766
3171
|
}
|
|
2767
3172
|
|
|
2768
|
-
function
|
|
2769
|
-
|
|
2770
|
-
|
|
3173
|
+
function planVitest(builder, options) {
|
|
3174
|
+
if (options == null) {
|
|
3175
|
+
return;
|
|
3176
|
+
}
|
|
3177
|
+
builder.addDevDependency("vitest");
|
|
3178
|
+
const template = builder.options.template ?? "vanilla";
|
|
2771
3179
|
const baseTemplate = getBaseTemplate(template);
|
|
2772
3180
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2773
3181
|
if (isReact) {
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
3182
|
+
builder.addDevDependency("@testing-library/react");
|
|
3183
|
+
builder.addDevDependency("@testing-library/dom");
|
|
3184
|
+
builder.addDevDependency("jsdom");
|
|
2777
3185
|
}
|
|
2778
3186
|
if (isReact) {
|
|
2779
|
-
|
|
3187
|
+
builder.configureVite({ test: { environment: "jsdom" } });
|
|
2780
3188
|
}
|
|
2781
|
-
|
|
2782
|
-
|
|
3189
|
+
builder.addScripts(packageJsonScripts.test.vitest);
|
|
3190
|
+
builder.inject(
|
|
2783
3191
|
"readme-tools",
|
|
2784
3192
|
"[Vitest](https://vitest.dev/) - Fast unit test framework powered by Vite"
|
|
2785
3193
|
);
|
|
2786
3194
|
}
|
|
2787
3195
|
|
|
2788
|
-
function
|
|
2789
|
-
if (options == null || getPackageManagerName(
|
|
3196
|
+
function planViverse(builder, options) {
|
|
3197
|
+
if (options == null || getPackageManagerName(builder.options.packageManager) !== "npm") {
|
|
2790
3198
|
return;
|
|
2791
3199
|
}
|
|
2792
|
-
|
|
3200
|
+
builder.addFile(".github/workflows/viverse.yml", {
|
|
2793
3201
|
type: "text",
|
|
2794
3202
|
content: `name: Deploy to Viverse
|
|
2795
3203
|
|
|
@@ -2840,12 +3248,12 @@ jobs:
|
|
|
2840
3248
|
run: npx viverse-cli auth login -e \${{ secrets.VIVERSE_EMAIL }} -p \${{ secrets.VIVERSE_PASSWORD }}
|
|
2841
3249
|
|
|
2842
3250
|
- name: Deploy to Viverse
|
|
2843
|
-
run: npx viverse-cli app publish ./dist --auto-create-app --name ${
|
|
3251
|
+
run: npx viverse-cli app publish ./dist --auto-create-app --name ${builder.options.name}
|
|
2844
3252
|
|
|
2845
3253
|
`
|
|
2846
3254
|
});
|
|
2847
|
-
|
|
2848
|
-
|
|
3255
|
+
builder.addDependency("@viverse/cli");
|
|
3256
|
+
builder.inject(
|
|
2849
3257
|
"readme-start",
|
|
2850
3258
|
`A GitHub CI/CD workflow for publishing to Viverse is configured.
|
|
2851
3259
|
|
|
@@ -2858,36 +3266,36 @@ You can also upload your project manually using the Viverse CLI:
|
|
|
2858
3266
|
\`\`\`bash
|
|
2859
3267
|
viverse-cli auth login -e <email> -p <password>
|
|
2860
3268
|
npm run build
|
|
2861
|
-
viverse-cli app publish ./dist --auto-create-app --name ${
|
|
3269
|
+
viverse-cli app publish ./dist --auto-create-app --name ${builder.options.name}
|
|
2862
3270
|
\`\`\`
|
|
2863
3271
|
`
|
|
2864
3272
|
);
|
|
2865
3273
|
}
|
|
2866
3274
|
|
|
2867
|
-
function
|
|
3275
|
+
function planXr(builder, options) {
|
|
2868
3276
|
if (options == null || options === false) {
|
|
2869
3277
|
return;
|
|
2870
3278
|
}
|
|
2871
3279
|
if (options === true) {
|
|
2872
3280
|
options = {};
|
|
2873
3281
|
}
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
3282
|
+
builder.addDependency("@react-three/xr");
|
|
3283
|
+
builder.addDependency("@vitejs/plugin-basic-ssl");
|
|
3284
|
+
builder.inject("import", "import { XR, createXRStore } from '@react-three/xr'");
|
|
3285
|
+
builder.inject(
|
|
2878
3286
|
`global-start`,
|
|
2879
3287
|
`const store = createXRStore(${JSON.stringify(options.storeOptions ?? {})})`
|
|
2880
3288
|
);
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
3289
|
+
builder.inject("scene-start", "<XR store={store}>");
|
|
3290
|
+
builder.inject("scene-end", "</XR>");
|
|
3291
|
+
builder.inject("vite-config-import", "import basicSsl from '@vitejs/plugin-basic-ssl'");
|
|
3292
|
+
builder.configureVite({
|
|
2885
3293
|
server: {
|
|
2886
3294
|
host: true
|
|
2887
3295
|
},
|
|
2888
3296
|
plugins: ["$raw:basicSsl()"]
|
|
2889
3297
|
});
|
|
2890
|
-
|
|
3298
|
+
builder.inject(
|
|
2891
3299
|
"dom-start",
|
|
2892
3300
|
`<div style={{
|
|
2893
3301
|
display: "flex",
|
|
@@ -2919,55 +3327,226 @@ function generateXr(generator, options) {
|
|
|
2919
3327
|
Enter VR
|
|
2920
3328
|
</button></div>`
|
|
2921
3329
|
);
|
|
2922
|
-
|
|
3330
|
+
builder.inject(
|
|
2923
3331
|
"readme-libraries",
|
|
2924
3332
|
`[@react-three/xr](https://pmndrs.github.io/xr/docs/) - VR/AR support for @react-three/fiber`
|
|
2925
3333
|
);
|
|
2926
3334
|
}
|
|
2927
3335
|
|
|
2928
|
-
function
|
|
3336
|
+
function planZustand(builder, options) {
|
|
2929
3337
|
if (options == null) {
|
|
2930
3338
|
return;
|
|
2931
3339
|
}
|
|
2932
|
-
|
|
2933
|
-
|
|
3340
|
+
builder.addDependency("zustand");
|
|
3341
|
+
builder.inject(
|
|
2934
3342
|
"readme-libraries",
|
|
2935
3343
|
`[zustand](https://zustand.docs.pmnd.rs/) - small, fast and scalable state-management solution`
|
|
2936
3344
|
);
|
|
2937
3345
|
}
|
|
2938
3346
|
|
|
2939
|
-
function
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
3347
|
+
function resolveProjectPlanInput(options) {
|
|
3348
|
+
const packageManager = options.packageManager ?? { name: "pnpm" };
|
|
3349
|
+
return {
|
|
3350
|
+
project: {
|
|
3351
|
+
githubUserName: options.githubUserName,
|
|
3352
|
+
githubRepoName: options.githubRepoName,
|
|
3353
|
+
name: options.name,
|
|
3354
|
+
projectType: options.projectType,
|
|
3355
|
+
template: options.template
|
|
3356
|
+
},
|
|
3357
|
+
aiAgents: {
|
|
3358
|
+
tool: "ai-agents",
|
|
3359
|
+
config: {
|
|
3360
|
+
platforms: options.aiPlatforms ?? []
|
|
3361
|
+
}
|
|
3362
|
+
},
|
|
3363
|
+
formatter: {
|
|
3364
|
+
tool: options.formatter ?? "prettier",
|
|
3365
|
+
config: structuredClone(defaultFormatterMetaConfig)
|
|
3366
|
+
},
|
|
3367
|
+
linter: {
|
|
3368
|
+
tool: options.linter ?? "oxlint",
|
|
3369
|
+
config: structuredClone(defaultLinterMetaConfig)
|
|
3370
|
+
},
|
|
3371
|
+
testing: {
|
|
3372
|
+
tool: options.testing ?? (options.projectType === "library" ? "vitest" : "none"),
|
|
3373
|
+
config: {}
|
|
3374
|
+
},
|
|
3375
|
+
typescript: {
|
|
3376
|
+
tool: "typescript",
|
|
3377
|
+
config: {
|
|
3378
|
+
configStrategy: options.configStrategy
|
|
3379
|
+
}
|
|
3380
|
+
},
|
|
3381
|
+
ide: {
|
|
3382
|
+
tool: options.ide ?? "vscode",
|
|
3383
|
+
config: {}
|
|
3384
|
+
},
|
|
3385
|
+
packageManager: {
|
|
3386
|
+
tool: packageManager.name,
|
|
3387
|
+
config: {
|
|
3388
|
+
version: packageManager.version,
|
|
3389
|
+
pnpmManageVersions: options.pnpmManageVersions
|
|
3390
|
+
}
|
|
3391
|
+
},
|
|
3392
|
+
libraryBundler: {
|
|
3393
|
+
tool: options.libraryBundler ?? "unbuild",
|
|
3394
|
+
config: {}
|
|
3395
|
+
},
|
|
3396
|
+
features: {
|
|
3397
|
+
fiber: options.fiber,
|
|
3398
|
+
handle: options.handle,
|
|
3399
|
+
drei: options.drei,
|
|
3400
|
+
koota: options.koota,
|
|
3401
|
+
leva: options.leva,
|
|
3402
|
+
offscreen: options.offscreen,
|
|
3403
|
+
postprocessing: options.postprocessing,
|
|
3404
|
+
rapier: options.rapier,
|
|
3405
|
+
triplex: options.triplex,
|
|
3406
|
+
viverse: options.viverse,
|
|
3407
|
+
uikit: options.uikit,
|
|
3408
|
+
xr: options.xr,
|
|
3409
|
+
zustand: options.zustand,
|
|
3410
|
+
githubPages: options.githubPages
|
|
3411
|
+
},
|
|
3412
|
+
context: {
|
|
3413
|
+
dependencies: options.dependencies,
|
|
3414
|
+
engine: options.engine,
|
|
3415
|
+
files: options.files,
|
|
3416
|
+
injections: options.injections,
|
|
3417
|
+
replacements: options.replacements,
|
|
3418
|
+
versions: options.versions,
|
|
3419
|
+
workspaceRoot: options.workspaceRoot,
|
|
3420
|
+
workspaceDependencies: options.workspaceDependencies
|
|
2959
3421
|
}
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
3422
|
+
};
|
|
3423
|
+
}
|
|
3424
|
+
function projectPlanInputToOptions(input) {
|
|
3425
|
+
return {
|
|
3426
|
+
...input.project,
|
|
3427
|
+
aiPlatforms: input.aiAgents.config.platforms.length > 0 ? input.aiAgents.config.platforms : void 0,
|
|
3428
|
+
formatter: input.formatter.tool,
|
|
3429
|
+
linter: input.linter.tool,
|
|
3430
|
+
testing: input.testing.tool,
|
|
3431
|
+
configStrategy: input.typescript.config.configStrategy,
|
|
3432
|
+
ide: input.ide.tool,
|
|
3433
|
+
packageManager: packageManagerSpecFromInput(input.packageManager),
|
|
3434
|
+
pnpmManageVersions: input.packageManager.config.pnpmManageVersions,
|
|
3435
|
+
libraryBundler: input.libraryBundler.tool,
|
|
3436
|
+
...input.features,
|
|
3437
|
+
dependencies: input.context.dependencies,
|
|
3438
|
+
engine: input.context.engine,
|
|
3439
|
+
files: input.context.files,
|
|
3440
|
+
injections: input.context.injections,
|
|
3441
|
+
replacements: input.context.replacements,
|
|
3442
|
+
versions: input.context.versions,
|
|
3443
|
+
workspaceRoot: input.context.workspaceRoot,
|
|
3444
|
+
workspaceDependencies: input.context.workspaceDependencies
|
|
3445
|
+
};
|
|
3446
|
+
}
|
|
3447
|
+
function resolveWorkspacePlanInput(params) {
|
|
3448
|
+
return {
|
|
3449
|
+
project: {
|
|
3450
|
+
name: params.name
|
|
3451
|
+
},
|
|
3452
|
+
aiAgents: {
|
|
3453
|
+
tool: "ai-agents",
|
|
3454
|
+
config: {
|
|
3455
|
+
platforms: params.aiPlatforms ?? []
|
|
3456
|
+
}
|
|
3457
|
+
},
|
|
3458
|
+
formatter: {
|
|
3459
|
+
tool: params.formatter,
|
|
3460
|
+
config: structuredClone(defaultFormatterMetaConfig)
|
|
3461
|
+
},
|
|
3462
|
+
linter: {
|
|
3463
|
+
tool: params.linter,
|
|
3464
|
+
config: structuredClone(defaultLinterMetaConfig)
|
|
3465
|
+
},
|
|
3466
|
+
ide: {
|
|
3467
|
+
tool: params.ide ?? "vscode",
|
|
3468
|
+
config: {}
|
|
3469
|
+
},
|
|
3470
|
+
packageManager: {
|
|
3471
|
+
tool: params.packageManager.name,
|
|
3472
|
+
config: {
|
|
3473
|
+
version: params.packageManager.version,
|
|
3474
|
+
pnpmManageVersions: params.pnpmManageVersions
|
|
3475
|
+
}
|
|
3476
|
+
},
|
|
3477
|
+
context: {
|
|
3478
|
+
engine: params.engine,
|
|
3479
|
+
pnpmManageVersions: params.pnpmManageVersions,
|
|
3480
|
+
versions: params.versions
|
|
2963
3481
|
}
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
return
|
|
3482
|
+
};
|
|
3483
|
+
}
|
|
3484
|
+
function workspacePlanInputToMonorepoParams(input) {
|
|
3485
|
+
return {
|
|
3486
|
+
name: input.project.name,
|
|
3487
|
+
linter: input.linter.tool,
|
|
3488
|
+
formatter: input.formatter.tool,
|
|
3489
|
+
packageManager: packageManagerSpecFromInput(input.packageManager),
|
|
3490
|
+
pnpmManageVersions: input.context.pnpmManageVersions,
|
|
3491
|
+
engine: input.context.engine,
|
|
3492
|
+
versions: input.context.versions,
|
|
3493
|
+
aiPlatforms: input.aiAgents.config.platforms.length > 0 ? input.aiAgents.config.platforms : void 0,
|
|
3494
|
+
ide: input.ide.tool
|
|
3495
|
+
};
|
|
3496
|
+
}
|
|
3497
|
+
function isProjectPlanInput(input) {
|
|
3498
|
+
return "project" in input && "formatter" in input && typeof input.formatter === "object";
|
|
3499
|
+
}
|
|
3500
|
+
function isWorkspacePlanInput(input) {
|
|
3501
|
+
return "project" in input && "formatter" in input && typeof input.formatter === "object";
|
|
3502
|
+
}
|
|
3503
|
+
function packageManagerSpecFromInput(packageManager) {
|
|
3504
|
+
return {
|
|
3505
|
+
name: packageManager.tool,
|
|
3506
|
+
version: packageManager.config.version
|
|
3507
|
+
};
|
|
3508
|
+
}
|
|
3509
|
+
|
|
3510
|
+
async function resolveProjectFacts(input) {
|
|
3511
|
+
const options = projectPlanInputToOptions(input);
|
|
3512
|
+
options.packageManager = await resolvePackageManager(options);
|
|
3513
|
+
options.engine = await resolveEngine(options);
|
|
3514
|
+
options.versions = await resolveProjectPackageVersions(options);
|
|
3515
|
+
return resolveProjectPlanInput(options);
|
|
3516
|
+
}
|
|
3517
|
+
async function resolveWorkspaceFacts(input) {
|
|
3518
|
+
const params = workspacePlanInputToMonorepoParams(input);
|
|
3519
|
+
const options = {
|
|
3520
|
+
name: params.name,
|
|
3521
|
+
linter: params.linter,
|
|
3522
|
+
formatter: params.formatter,
|
|
3523
|
+
packageManager: params.packageManager,
|
|
3524
|
+
engine: params.engine,
|
|
3525
|
+
pnpmManageVersions: params.pnpmManageVersions,
|
|
3526
|
+
versions: params.versions
|
|
3527
|
+
};
|
|
3528
|
+
const packageManager = await resolvePackageManager(options);
|
|
3529
|
+
const engine = await resolveEngine(options);
|
|
3530
|
+
const versions = await resolveMonorepoRootPackageVersions({
|
|
3531
|
+
linter: params.linter,
|
|
3532
|
+
formatter: params.formatter,
|
|
3533
|
+
engine,
|
|
3534
|
+
versions: params.versions
|
|
3535
|
+
});
|
|
3536
|
+
return resolveWorkspacePlanInput({
|
|
3537
|
+
...params,
|
|
3538
|
+
packageManager,
|
|
3539
|
+
engine,
|
|
3540
|
+
versions
|
|
3541
|
+
});
|
|
2968
3542
|
}
|
|
2969
3543
|
|
|
2970
|
-
function
|
|
3544
|
+
async function planProject(input) {
|
|
3545
|
+
const planInput = isProjectPlanInput(input) ? input : resolveProjectPlanInput(input);
|
|
3546
|
+
return createProjectPlan(await resolveProjectFacts(planInput));
|
|
3547
|
+
}
|
|
3548
|
+
function createProjectPlan(planInput) {
|
|
3549
|
+
const options = projectPlanInputToOptions(planInput);
|
|
2971
3550
|
const clonedOptions = structuredClone(options);
|
|
2972
3551
|
const template = clonedOptions.template ?? "vanilla";
|
|
2973
3552
|
const baseTemplate = getBaseTemplate(template);
|
|
@@ -2976,7 +3555,8 @@ function generate(options) {
|
|
|
2976
3555
|
const isReact = baseTemplate === "react";
|
|
2977
3556
|
const isR3f = baseTemplate === "r3f";
|
|
2978
3557
|
const isLibrary = clonedOptions.projectType === "library";
|
|
2979
|
-
const libraryBundler =
|
|
3558
|
+
const libraryBundler = planInput.libraryBundler.tool;
|
|
3559
|
+
const ide = planInput.ide.tool;
|
|
2980
3560
|
const files = {
|
|
2981
3561
|
...clonedOptions.files
|
|
2982
3562
|
};
|
|
@@ -3010,7 +3590,7 @@ function generate(options) {
|
|
|
3010
3590
|
}
|
|
3011
3591
|
}
|
|
3012
3592
|
if (language === "typescript") {
|
|
3013
|
-
const tsResult =
|
|
3593
|
+
const tsResult = renderTypescriptConfig({
|
|
3014
3594
|
baseTemplate,
|
|
3015
3595
|
useConfigPackage: clonedOptions.workspaceRoot != null,
|
|
3016
3596
|
configStrategy: clonedOptions.configStrategy,
|
|
@@ -3022,10 +3602,7 @@ function generate(options) {
|
|
|
3022
3602
|
}
|
|
3023
3603
|
const codeSnippets = {};
|
|
3024
3604
|
const vscodeSettings = {};
|
|
3025
|
-
const scripts =
|
|
3026
|
-
dev: "vite",
|
|
3027
|
-
build: "vite build"
|
|
3028
|
-
};
|
|
3605
|
+
const scripts = {};
|
|
3029
3606
|
if (!isLibrary && (isReact || isR3f)) {
|
|
3030
3607
|
codeSnippets["vite-config-import"] = ["import react from '@vitejs/plugin-react'"];
|
|
3031
3608
|
}
|
|
@@ -3044,7 +3621,7 @@ function generate(options) {
|
|
|
3044
3621
|
viteConfig.resolve = { dedupe: ["three"] };
|
|
3045
3622
|
}
|
|
3046
3623
|
const isMonorepoPackage = clonedOptions.workspaceRoot != null;
|
|
3047
|
-
const
|
|
3624
|
+
const builder = {
|
|
3048
3625
|
options: clonedOptions,
|
|
3049
3626
|
versions,
|
|
3050
3627
|
getVersion(name2) {
|
|
@@ -3074,8 +3651,11 @@ function generate(options) {
|
|
|
3074
3651
|
addFile(path, content) {
|
|
3075
3652
|
files[path] = content;
|
|
3076
3653
|
},
|
|
3654
|
+
addScripts(nextScripts) {
|
|
3655
|
+
Object.assign(scripts, nextScripts);
|
|
3656
|
+
},
|
|
3077
3657
|
addScript(name2, command) {
|
|
3078
|
-
|
|
3658
|
+
this.addScripts({ [name2]: command });
|
|
3079
3659
|
},
|
|
3080
3660
|
inject(location, code) {
|
|
3081
3661
|
let entries = codeSnippets[location];
|
|
@@ -3095,71 +3675,61 @@ function generate(options) {
|
|
|
3095
3675
|
}
|
|
3096
3676
|
};
|
|
3097
3677
|
if (isR3f) {
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3678
|
+
planDrei(builder, planInput.features.drei);
|
|
3679
|
+
planHandle(builder, planInput.features.handle);
|
|
3680
|
+
planKoota(builder, planInput.features.koota);
|
|
3681
|
+
planLeva(builder, planInput.features.leva);
|
|
3682
|
+
planOffscreen(builder, planInput.features.offscreen);
|
|
3683
|
+
planPostprocessing(builder, planInput.features.postprocessing);
|
|
3684
|
+
planRapier(builder, planInput.features.rapier);
|
|
3685
|
+
planUikit(builder, planInput.features.uikit);
|
|
3686
|
+
planXr(builder, planInput.features.xr);
|
|
3687
|
+
planZustand(builder, planInput.features.zustand);
|
|
3688
|
+
planFiber(builder, planInput.features.fiber);
|
|
3689
|
+
planTriplex(builder, planInput.features.triplex);
|
|
3690
|
+
planViverse(builder, planInput.features.viverse);
|
|
3111
3691
|
}
|
|
3112
3692
|
if (!isLibrary) {
|
|
3113
|
-
|
|
3693
|
+
planGithubPages(builder, planInput.features.githubPages);
|
|
3114
3694
|
}
|
|
3115
3695
|
if (isLibrary) {
|
|
3116
3696
|
if (libraryBundler === "unbuild") {
|
|
3117
|
-
|
|
3697
|
+
planUnbuild(builder);
|
|
3118
3698
|
} else if (libraryBundler === "tsdown") {
|
|
3119
|
-
|
|
3699
|
+
planTsdown(builder);
|
|
3120
3700
|
}
|
|
3121
|
-
const packageManager2 = getPackageManagerName(clonedOptions.packageManager);
|
|
3122
|
-
generator.addScript("release", `${packageManager2} run build && ${packageManager2} publish`);
|
|
3123
3701
|
}
|
|
3124
|
-
const testing =
|
|
3702
|
+
const testing = planInput.testing.tool;
|
|
3125
3703
|
if (testing === "vitest") {
|
|
3126
|
-
|
|
3127
|
-
}
|
|
3128
|
-
const linter =
|
|
3129
|
-
const formatter =
|
|
3130
|
-
if (linter === "eslint") {
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
} else if (linter === "
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
} else if (linter === "biome") {
|
|
3139
|
-
generateBiome(generator, {
|
|
3140
|
-
linter: true,
|
|
3141
|
-
formatter: formatter === "biome"
|
|
3704
|
+
planVitest(builder, planInput.testing);
|
|
3705
|
+
}
|
|
3706
|
+
const linter = planInput.linter.tool;
|
|
3707
|
+
const formatter = planInput.formatter.tool;
|
|
3708
|
+
if (planInput.linter.tool === "eslint") {
|
|
3709
|
+
planEslint(builder, planInput.linter);
|
|
3710
|
+
} else if (planInput.linter.tool === "oxlint") {
|
|
3711
|
+
planOxlint(builder, planInput.linter);
|
|
3712
|
+
} else if (planInput.linter.tool === "biome") {
|
|
3713
|
+
planBiome(builder, {
|
|
3714
|
+
linter: planInput.linter,
|
|
3715
|
+
formatter: planInput.formatter.tool === "biome" ? planInput.formatter : void 0
|
|
3142
3716
|
});
|
|
3143
|
-
generator.addVscodeSetting("eslint.enable", false);
|
|
3144
|
-
generator.addVscodeSetting("oxc.enable", false);
|
|
3145
3717
|
}
|
|
3146
|
-
if (formatter === "prettier") {
|
|
3147
|
-
|
|
3148
|
-
} else if (formatter === "oxfmt") {
|
|
3149
|
-
|
|
3150
|
-
} else if (formatter === "biome" && linter !== "biome") {
|
|
3151
|
-
|
|
3152
|
-
generator.addVscodeSetting("eslint.enable", false);
|
|
3153
|
-
generator.addVscodeSetting("oxc.enable", false);
|
|
3718
|
+
if (planInput.formatter.tool === "prettier") {
|
|
3719
|
+
planPrettier(builder, planInput.formatter);
|
|
3720
|
+
} else if (planInput.formatter.tool === "oxfmt") {
|
|
3721
|
+
planOxfmt(builder, planInput.formatter);
|
|
3722
|
+
} else if (planInput.formatter.tool === "biome" && planInput.linter.tool !== "biome") {
|
|
3723
|
+
planBiome(builder, { formatter: planInput.formatter });
|
|
3154
3724
|
}
|
|
3155
3725
|
for (const { code, location } of clonedOptions.injections ?? []) {
|
|
3156
|
-
|
|
3726
|
+
builder.inject(location, code);
|
|
3157
3727
|
}
|
|
3158
3728
|
if (!isLibrary) {
|
|
3159
|
-
files["vite.config.ts"] =
|
|
3729
|
+
files["vite.config.ts"] = renderViteConfig({ viteConfig, codeSnippets });
|
|
3160
3730
|
}
|
|
3161
3731
|
const packageManager = getPackageManagerName(options.packageManager);
|
|
3162
|
-
files["README.md"] =
|
|
3732
|
+
files["README.md"] = renderReadme({
|
|
3163
3733
|
name,
|
|
3164
3734
|
baseTemplate,
|
|
3165
3735
|
isLibrary,
|
|
@@ -3169,7 +3739,7 @@ function generate(options) {
|
|
|
3169
3739
|
});
|
|
3170
3740
|
Object.assign(
|
|
3171
3741
|
files,
|
|
3172
|
-
|
|
3742
|
+
renderSourceFiles({
|
|
3173
3743
|
name,
|
|
3174
3744
|
baseTemplate,
|
|
3175
3745
|
language,
|
|
@@ -3181,7 +3751,7 @@ function generate(options) {
|
|
|
3181
3751
|
if (testing === "vitest") {
|
|
3182
3752
|
Object.assign(
|
|
3183
3753
|
files,
|
|
3184
|
-
|
|
3754
|
+
renderTestFiles({
|
|
3185
3755
|
baseTemplate,
|
|
3186
3756
|
language,
|
|
3187
3757
|
isLibrary
|
|
@@ -3190,7 +3760,7 @@ function generate(options) {
|
|
|
3190
3760
|
}
|
|
3191
3761
|
Object.assign(
|
|
3192
3762
|
files,
|
|
3193
|
-
|
|
3763
|
+
renderPackageJson({
|
|
3194
3764
|
name,
|
|
3195
3765
|
language,
|
|
3196
3766
|
isLibrary,
|
|
@@ -3202,25 +3772,54 @@ function generate(options) {
|
|
|
3202
3772
|
workspaceDependencies: clonedOptions.workspaceDependencies
|
|
3203
3773
|
}).files
|
|
3204
3774
|
);
|
|
3205
|
-
if (!isMonorepoPackage) {
|
|
3206
|
-
Object.assign(
|
|
3775
|
+
if (!isMonorepoPackage && ide === "vscode") {
|
|
3776
|
+
Object.assign(
|
|
3777
|
+
files,
|
|
3778
|
+
renderVscodeFiles$1({
|
|
3779
|
+
codeSnippets,
|
|
3780
|
+
vscodeSettings,
|
|
3781
|
+
linter,
|
|
3782
|
+
formatter,
|
|
3783
|
+
configStrategy: clonedOptions.configStrategy,
|
|
3784
|
+
isMonorepo: false,
|
|
3785
|
+
packageManager
|
|
3786
|
+
})
|
|
3787
|
+
);
|
|
3207
3788
|
}
|
|
3208
3789
|
if (!isMonorepoPackage) {
|
|
3209
|
-
files[".
|
|
3210
|
-
files[".
|
|
3790
|
+
files[".editorconfig"] = renderEditorConfig();
|
|
3791
|
+
files[".gitignore"] = renderGitignore("standalone");
|
|
3792
|
+
files[".gitattributes"] = { type: "text", content: gitAttributesContent };
|
|
3211
3793
|
}
|
|
3212
|
-
if (!isMonorepoPackage &&
|
|
3213
|
-
|
|
3794
|
+
if (!isMonorepoPackage && planInput.aiAgents.config.platforms.length > 0) {
|
|
3795
|
+
renderAiFiles(files, {
|
|
3214
3796
|
name,
|
|
3215
3797
|
packageManager: getPackageManagerName(clonedOptions.packageManager),
|
|
3216
3798
|
linter: clonedOptions.linter ?? "oxlint",
|
|
3217
3799
|
formatter: clonedOptions.formatter ?? "prettier",
|
|
3218
3800
|
isMonorepo: false,
|
|
3219
3801
|
configStrategy: clonedOptions.configStrategy,
|
|
3220
|
-
|
|
3802
|
+
hasTypecheck: language === "typescript",
|
|
3803
|
+
platforms: planInput.aiAgents.config.platforms
|
|
3221
3804
|
});
|
|
3222
3805
|
}
|
|
3223
|
-
return
|
|
3806
|
+
return {
|
|
3807
|
+
files,
|
|
3808
|
+
dependencies,
|
|
3809
|
+
devDependencies,
|
|
3810
|
+
peerDependencies,
|
|
3811
|
+
scripts,
|
|
3812
|
+
vscodeSettings,
|
|
3813
|
+
vscodeExtensions: [...new Set(codeSnippets["vscode-extension-suggestion"] ?? [])],
|
|
3814
|
+
injections: Object.entries(codeSnippets).flatMap(
|
|
3815
|
+
([location, entries]) => (entries ?? []).map((code) => ({
|
|
3816
|
+
location,
|
|
3817
|
+
code
|
|
3818
|
+
}))
|
|
3819
|
+
),
|
|
3820
|
+
replacements,
|
|
3821
|
+
warnings: []
|
|
3822
|
+
};
|
|
3224
3823
|
}
|
|
3225
3824
|
function resolveDependencySemver(name, versions, options = {}) {
|
|
3226
3825
|
if (options.version != null) {
|
|
@@ -3229,38 +3828,66 @@ function resolveDependencySemver(name, versions, options = {}) {
|
|
|
3229
3828
|
return formatResolvedPackageVersion(versions, name, options.prefix);
|
|
3230
3829
|
}
|
|
3231
3830
|
|
|
3831
|
+
async function planWorkspace(input) {
|
|
3832
|
+
const planInput = isWorkspacePlanInput(input) ? input : resolveWorkspacePlanInput(input);
|
|
3833
|
+
const resolvedInput = await resolveWorkspaceFacts(planInput);
|
|
3834
|
+
const { files } = renderMonorepo(workspacePlanInputToMonorepoParams(resolvedInput));
|
|
3835
|
+
return {
|
|
3836
|
+
files,
|
|
3837
|
+
dependencies: {},
|
|
3838
|
+
devDependencies: {},
|
|
3839
|
+
peerDependencies: {},
|
|
3840
|
+
scripts: {},
|
|
3841
|
+
vscodeSettings: {},
|
|
3842
|
+
vscodeExtensions: [],
|
|
3843
|
+
injections: [],
|
|
3844
|
+
replacements: [],
|
|
3845
|
+
warnings: []
|
|
3846
|
+
};
|
|
3847
|
+
}
|
|
3848
|
+
|
|
3232
3849
|
exports.AI_PLATFORM_HINTS = AI_PLATFORM_HINTS;
|
|
3233
3850
|
exports.AI_PLATFORM_LABELS = AI_PLATFORM_LABELS;
|
|
3234
3851
|
exports.ALL_AI_PLATFORMS = ALL_AI_PLATFORMS;
|
|
3235
3852
|
exports.detectTooling = detectTooling;
|
|
3236
3853
|
exports.formatResolvedPackageVersion = formatResolvedPackageVersion;
|
|
3237
|
-
exports.generate = generate;
|
|
3238
|
-
exports.generateAiFiles = generateAiFiles;
|
|
3239
|
-
exports.generateEslintConfigPackage = generateEslintConfigPackage;
|
|
3240
|
-
exports.generateGitignore = generateGitignore;
|
|
3241
|
-
exports.generateMonorepo = generateMonorepo;
|
|
3242
|
-
exports.generateOxfmtConfigPackage = generateOxfmtConfigPackage;
|
|
3243
|
-
exports.generateOxlintConfigPackage = generateOxlintConfigPackage;
|
|
3244
|
-
exports.generatePrettierConfigPackage = generatePrettierConfigPackage;
|
|
3245
3854
|
exports.generateRandomName = generateRandomName;
|
|
3246
|
-
exports.generateTypescriptConfigPackage = generateTypescriptConfigPackage;
|
|
3247
|
-
exports.generateVscodeFiles = generateVscodeFiles;
|
|
3248
3855
|
exports.getBaseTemplate = getBaseTemplate;
|
|
3249
3856
|
exports.getEngineName = getEngineName;
|
|
3250
3857
|
exports.getLanguageFromTemplate = getLanguageFromTemplate;
|
|
3251
3858
|
exports.getLatestNodeVersion = getLatestNodeVersion;
|
|
3252
3859
|
exports.getLatestNpmCliVersion = getLatestNpmCliVersion;
|
|
3860
|
+
exports.getLatestNpmMajorVersion = getLatestNpmMajorVersion;
|
|
3253
3861
|
exports.getLatestNpmVersion = getLatestNpmVersion;
|
|
3254
3862
|
exports.getLatestPnpmVersion = getLatestPnpmVersion;
|
|
3255
3863
|
exports.getLatestYarnVersion = getLatestYarnVersion;
|
|
3256
3864
|
exports.getPackageManagerName = getPackageManagerName;
|
|
3257
3865
|
exports.getResolvedPackageVersion = getResolvedPackageVersion;
|
|
3258
|
-
exports.
|
|
3866
|
+
exports.merge = merge;
|
|
3867
|
+
exports.mergePackageJsonScripts = mergePackageJsonScripts;
|
|
3868
|
+
exports.packageJsonScripts = packageJsonScripts;
|
|
3259
3869
|
exports.parseEngine = parseEngine;
|
|
3260
3870
|
exports.parsePackageManager = parsePackageManager;
|
|
3261
3871
|
exports.parseWorkspaceYamlContent = parseWorkspaceYamlContent;
|
|
3262
|
-
exports.
|
|
3872
|
+
exports.planProject = planProject;
|
|
3873
|
+
exports.planWorkspace = planWorkspace;
|
|
3874
|
+
exports.projectPlanInputToOptions = projectPlanInputToOptions;
|
|
3875
|
+
exports.renderAiFiles = renderAiFiles;
|
|
3876
|
+
exports.renderEditorConfig = renderEditorConfig;
|
|
3877
|
+
exports.renderEslintConfigPackage = renderEslintConfigPackage;
|
|
3878
|
+
exports.renderGitignore = renderGitignore;
|
|
3879
|
+
exports.renderOxfmtConfigPackage = renderOxfmtConfigPackage;
|
|
3880
|
+
exports.renderOxlintConfig = renderOxlintConfig;
|
|
3881
|
+
exports.renderOxlintConfigPackage = renderOxlintConfigPackage;
|
|
3882
|
+
exports.renderPrettierConfigPackage = renderPrettierConfigPackage;
|
|
3883
|
+
exports.renderTypescriptConfigPackage = renderTypescriptConfigPackage;
|
|
3884
|
+
exports.renderVscodeFiles = renderVscodeFiles;
|
|
3885
|
+
exports.renderVscodeFiles$1 = renderVscodeFiles$1;
|
|
3886
|
+
exports.resolveDefaultPackageJsonScripts = resolveDefaultPackageJsonScripts;
|
|
3263
3887
|
exports.resolveMonorepoRootPackageVersions = resolveMonorepoRootPackageVersions;
|
|
3264
|
-
exports.
|
|
3265
|
-
exports.
|
|
3888
|
+
exports.resolveProjectPlanInput = resolveProjectPlanInput;
|
|
3889
|
+
exports.resolveWorkspacePlanInput = resolveWorkspacePlanInput;
|
|
3890
|
+
exports.toPrettierIgnoreContent = toPrettierIgnoreContent;
|
|
3891
|
+
exports.unique = unique;
|
|
3266
3892
|
exports.validatePackageName = validatePackageName;
|
|
3893
|
+
exports.workspacePlanInputToMonorepoParams = workspacePlanInputToMonorepoParams;
|