startx 0.4.0 → 0.6.1
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/.github/workflows/publish.yml +1 -1
- package/apps/cli/package.json +43 -0
- package/apps/cli/src/commands/ping.ts +10 -0
- package/apps/cli/src/index.ts +12 -0
- package/apps/cli/src/types.ts +0 -0
- package/apps/cli/src/utils/inquirer.ts +160 -0
- package/apps/core-server/package.json +4 -1
- package/{packages/cli → apps/startx-cli}/dist/index.mjs +2 -2
- package/apps/startx-cli/eslint.config.ts +4 -0
- package/{packages/cli → apps/startx-cli}/package.json +7 -4
- package/apps/startx-cli/src/commands/init.ts +415 -0
- package/apps/startx-cli/src/configs/deps.ts +45 -0
- package/apps/startx-cli/src/configs/files.ts +51 -0
- package/apps/startx-cli/src/configs/scripts.ts +158 -0
- package/apps/startx-cli/src/constants.ts +4 -0
- package/apps/startx-cli/src/index.ts +21 -0
- package/apps/startx-cli/src/types.ts +64 -0
- package/apps/startx-cli/src/utils/cli-utils.ts +104 -0
- package/apps/startx-cli/src/utils/config.ts +104 -0
- package/apps/startx-cli/src/utils/file-handler.ts +130 -0
- package/apps/startx-cli/src/utils/inquirer.ts +160 -0
- package/apps/startx-cli/tsconfig.json +12 -0
- package/apps/startx-cli/tsdown.config.ts +18 -0
- package/configs/eslint-config/package.json +1 -1
- package/configs/tsdown-config/package.json +1 -1
- package/configs/vitest-config/package.json +1 -1
- package/package.json +5 -4
- package/packages/@repo/constants/package.json +1 -1
- package/packages/@repo/db/package.json +5 -1
- package/packages/@repo/env/package.json +1 -1
- package/packages/@repo/lib/package.json +1 -1
- package/packages/@repo/logger/package.json +1 -1
- package/packages/@repo/mail/package.json +4 -1
- package/packages/@repo/mail/src/index.ts +0 -1
- package/packages/@repo/redis/package.json +1 -1
- package/packages/ui/package.json +1 -1
- package/startx.json +1 -0
- /package/{packages → apps}/cli/eslint.config.ts +0 -0
- /package/{packages → apps}/cli/tsconfig.json +0 -0
- /package/{packages → apps}/cli/tsdown.config.ts +0 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import { fsTool } from "@repo/lib/file-system-module";
|
|
2
|
+
import { logger } from "@repo/logger";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import z from "zod";
|
|
6
|
+
|
|
7
|
+
import { FileCheck } from "../configs/files";
|
|
8
|
+
import type { StartXPackageJson, TAGS } from "../types";
|
|
9
|
+
import { CliUtils } from "../utils/cli-utils";
|
|
10
|
+
import { FileHandler } from "../utils/file-handler";
|
|
11
|
+
import { CommonInquirer } from "../utils/inquirer";
|
|
12
|
+
|
|
13
|
+
type InitOptions = {
|
|
14
|
+
dir?: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type PackageWithJson = {
|
|
18
|
+
packageJson: StartXPackageJson | null;
|
|
19
|
+
type: "apps" | "configs" | "packages";
|
|
20
|
+
path: string;
|
|
21
|
+
name: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export class InitCommand {
|
|
25
|
+
static command = new Command("init")
|
|
26
|
+
.argument("[projectName]")
|
|
27
|
+
.option("-d, --dir <path>", "workspace directory")
|
|
28
|
+
.action(InitCommand.run.bind(InitCommand));
|
|
29
|
+
|
|
30
|
+
private static async run(projectName: string | undefined, options: InitOptions) {
|
|
31
|
+
const packageList: PackageWithJson[] = await Promise.all(
|
|
32
|
+
(await CliUtils.getPackageList()).map(async e => ({
|
|
33
|
+
...e,
|
|
34
|
+
packageJson: await CliUtils.parsePackageJson({ dir: e.path }),
|
|
35
|
+
}))
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const prefs = await InitCommand.getPrefs({
|
|
39
|
+
projectName,
|
|
40
|
+
options,
|
|
41
|
+
projects: packageList.filter(e => {
|
|
42
|
+
if (e.type !== "apps") return false;
|
|
43
|
+
if (e.packageJson?.startx?.mode === "silent") return false;
|
|
44
|
+
return true;
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const packages = await Promise.all(
|
|
49
|
+
packageList
|
|
50
|
+
.filter(e => e.type !== "apps")
|
|
51
|
+
.map(async e => ({
|
|
52
|
+
...e,
|
|
53
|
+
packageJson: await CliUtils.parsePackageJson({ dir: e.path }),
|
|
54
|
+
}))
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const config = await this.getConfigPrefs({
|
|
58
|
+
selectedApps: prefs.selectedApps,
|
|
59
|
+
packages,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const packagePrefs = await this.getPackagesPrefs({
|
|
63
|
+
selectedApps: prefs.selectedApps,
|
|
64
|
+
selectedPackages: config.selectedConfigs,
|
|
65
|
+
packages,
|
|
66
|
+
tags: config.tags,
|
|
67
|
+
});
|
|
68
|
+
await this.installWorkspace({
|
|
69
|
+
name: prefs.projectName,
|
|
70
|
+
tags: [...packagePrefs.tags, "runnable"],
|
|
71
|
+
dir: {
|
|
72
|
+
workspace: prefs.directory.workspace,
|
|
73
|
+
template: prefs.directory.template,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
await Promise.all(
|
|
78
|
+
packagePrefs.selectedPackages.concat(prefs.selectedApps).map(async pkg => {
|
|
79
|
+
const appDeps = new Map<string, string>();
|
|
80
|
+
const tags = new Set(packagePrefs.tags);
|
|
81
|
+
|
|
82
|
+
if (pkg.packageJson?.startx?.mode === "standalone") tags.add("runnable");
|
|
83
|
+
|
|
84
|
+
if (pkg.type === "apps") {
|
|
85
|
+
tags.add("runnable");
|
|
86
|
+
|
|
87
|
+
packagePrefs.selectedPackages
|
|
88
|
+
.filter(
|
|
89
|
+
e =>
|
|
90
|
+
e.packageJson?.startx?.mode !== "standalone" &&
|
|
91
|
+
e.packageJson?.startx?.iTags?.every(tag =>
|
|
92
|
+
pkg.packageJson?.startx?.tags?.includes(tag)
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
.forEach(e => appDeps.set(e.packageJson?.name || e.name, "workspace:^"));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
await this.installPackage({
|
|
99
|
+
packages: pkg,
|
|
100
|
+
directory: {
|
|
101
|
+
workspace: prefs.directory.workspace,
|
|
102
|
+
template: prefs.directory.template,
|
|
103
|
+
},
|
|
104
|
+
tags: Array.from(tags),
|
|
105
|
+
dependencies: Object.fromEntries(appDeps),
|
|
106
|
+
});
|
|
107
|
+
})
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private static async getPrefs(props: {
|
|
112
|
+
projectName?: string;
|
|
113
|
+
directory?: string;
|
|
114
|
+
options: InitOptions;
|
|
115
|
+
projects: PackageWithJson[];
|
|
116
|
+
}) {
|
|
117
|
+
if (!props.projectName) {
|
|
118
|
+
props.projectName = await CommonInquirer.getText({
|
|
119
|
+
message: "Project name",
|
|
120
|
+
name: "projectName",
|
|
121
|
+
schema: z.string().min(2).trim(),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Handling workspace directory
|
|
126
|
+
const directory = CliUtils.getDirectory();
|
|
127
|
+
let workspace;
|
|
128
|
+
if (props.options.dir) {
|
|
129
|
+
try {
|
|
130
|
+
workspace = path.resolve(directory.workspace, props.options.dir);
|
|
131
|
+
} catch {
|
|
132
|
+
throw new Error("Invalid template directory");
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
workspace = path.join(directory.workspace, props.projectName);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (props.projects.length === 0) {
|
|
139
|
+
throw new Error("No apps found");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const selectedAppNames = await CommonInquirer.choose({
|
|
143
|
+
message: "Select apps to install",
|
|
144
|
+
options: props.projects.map(e => e.name),
|
|
145
|
+
includeAllOption: true,
|
|
146
|
+
mode: "multiple",
|
|
147
|
+
required: true,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const selectedApps = props.projects.filter(e => selectedAppNames.includes(e.name));
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
projectName: props.projectName,
|
|
154
|
+
directory: {
|
|
155
|
+
workspace,
|
|
156
|
+
template: directory.template,
|
|
157
|
+
},
|
|
158
|
+
selectedApps,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private static async getConfigPrefs(props: {
|
|
163
|
+
packages: PackageWithJson[];
|
|
164
|
+
selectedApps: PackageWithJson[];
|
|
165
|
+
}) {
|
|
166
|
+
const tags = new Set<TAGS>(["common"]);
|
|
167
|
+
const configs = new Map<string, PackageWithJson>();
|
|
168
|
+
// Add additional tags from apps
|
|
169
|
+
props.selectedApps
|
|
170
|
+
.flatMap(app => app.packageJson?.startx?.gTags || [])
|
|
171
|
+
.forEach(tag => tags.add(tag));
|
|
172
|
+
|
|
173
|
+
// Add required configs from apps
|
|
174
|
+
props.selectedApps
|
|
175
|
+
.flatMap(app => [
|
|
176
|
+
...(app.packageJson?.startx?.requiredDeps || []),
|
|
177
|
+
...(app.packageJson?.startx?.requiredDevDeps || []),
|
|
178
|
+
])
|
|
179
|
+
.forEach(pkg => {
|
|
180
|
+
const config = props.packages.find(e => e.packageJson?.name === pkg);
|
|
181
|
+
if (config) configs.set(config.name, config);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const availableConfigs = props.packages.filter(e => {
|
|
185
|
+
if (e.type !== "configs") return false;
|
|
186
|
+
if (e.packageJson?.startx?.mode === "silent") {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
if (configs.has(e.name)) return false;
|
|
190
|
+
if (!e.packageJson?.startx?.iTags?.every(t => tags.has(t))) return false;
|
|
191
|
+
return true;
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
if (availableConfigs.length === 0)
|
|
195
|
+
return {
|
|
196
|
+
tags: Array.from(tags),
|
|
197
|
+
selectedConfigs: Array.from(configs.values()),
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const rawSelectedConfigs = await CommonInquirer.choose({
|
|
201
|
+
message: "Select configs to install",
|
|
202
|
+
options: availableConfigs.map(e => e.name),
|
|
203
|
+
includeAllOption: true,
|
|
204
|
+
mode: "multiple",
|
|
205
|
+
required: false,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
availableConfigs
|
|
209
|
+
.filter(e => rawSelectedConfigs.includes(e.name))
|
|
210
|
+
.forEach(e => configs.set(e.name, e));
|
|
211
|
+
|
|
212
|
+
if (tags.has("node")) {
|
|
213
|
+
const formatter: string | string[] = await CommonInquirer.choose({
|
|
214
|
+
message: "Select formatter",
|
|
215
|
+
options: ["prettier + biome", "prettier"],
|
|
216
|
+
mode: "single",
|
|
217
|
+
default: "prettier",
|
|
218
|
+
required: true,
|
|
219
|
+
});
|
|
220
|
+
if (formatter === "prettier") {
|
|
221
|
+
tags.add("prettier");
|
|
222
|
+
} else {
|
|
223
|
+
tags.add("biome");
|
|
224
|
+
tags.add("prettier");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Include required configs
|
|
229
|
+
Array.from(configs.values()).forEach(e => {
|
|
230
|
+
const requiredDeps = e.packageJson?.startx?.requiredDeps || [];
|
|
231
|
+
const requiredDevDeps = e.packageJson?.startx?.requiredDevDeps || [];
|
|
232
|
+
|
|
233
|
+
const required = [...requiredDeps, ...requiredDevDeps];
|
|
234
|
+
required.forEach(pkg => {
|
|
235
|
+
const config = props.packages.find(e => e.packageJson?.name === pkg);
|
|
236
|
+
if (config) {
|
|
237
|
+
configs.set(config.name, config);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Include all tags
|
|
243
|
+
Array.from(configs.values()).forEach(e => {
|
|
244
|
+
const gTags = e.packageJson?.startx?.gTags || [];
|
|
245
|
+
gTags.forEach(tag => tags.add(tag));
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
tags: Array.from(tags),
|
|
250
|
+
selectedConfigs: Array.from(configs.values()),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private static async getPackagesPrefs(props: {
|
|
255
|
+
tags: TAGS[];
|
|
256
|
+
packages: PackageWithJson[];
|
|
257
|
+
selectedApps: PackageWithJson[];
|
|
258
|
+
selectedPackages: PackageWithJson[];
|
|
259
|
+
}) {
|
|
260
|
+
const appTags = new Set<TAGS>(props.tags);
|
|
261
|
+
const packages = new Map<string, PackageWithJson>(props.selectedPackages.map(e => [e.name, e]));
|
|
262
|
+
const availablePackages = props.packages.filter(pkg => {
|
|
263
|
+
if (pkg.type !== "packages") return false;
|
|
264
|
+
if (pkg.packageJson?.startx?.mode === "silent") {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
if (packages.has(pkg.name)) return false;
|
|
268
|
+
if (!pkg.packageJson?.startx?.iTags?.every(t => appTags.has(t))) return false;
|
|
269
|
+
return true;
|
|
270
|
+
});
|
|
271
|
+
if (!availablePackages.length)
|
|
272
|
+
return {
|
|
273
|
+
selectedPackages: Array.from(packages.values()),
|
|
274
|
+
tags: Array.from(appTags),
|
|
275
|
+
};
|
|
276
|
+
const rawSelectedPackages = await CommonInquirer.choose({
|
|
277
|
+
message: "Select packages to install",
|
|
278
|
+
options: availablePackages.map(e => e.name),
|
|
279
|
+
includeAllOption: true,
|
|
280
|
+
mode: "multiple",
|
|
281
|
+
required: false,
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
availablePackages
|
|
285
|
+
.filter(e => rawSelectedPackages.includes(e.name))
|
|
286
|
+
.forEach(e => packages.set(e.name, e));
|
|
287
|
+
|
|
288
|
+
Array.from(packages.values()).forEach(e => {
|
|
289
|
+
const requiredDeps = e.packageJson?.startx?.requiredDeps || [];
|
|
290
|
+
const requiredDevDeps = e.packageJson?.startx?.requiredDevDeps || [];
|
|
291
|
+
|
|
292
|
+
const required = [...requiredDeps, ...requiredDevDeps];
|
|
293
|
+
required.forEach(tag => {
|
|
294
|
+
const config = props.packages.find(e => e.packageJson?.name === tag);
|
|
295
|
+
if (config) {
|
|
296
|
+
packages.set(config.name, config);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// Include all tags
|
|
302
|
+
Array.from(packages.values()).forEach(e => {
|
|
303
|
+
const gTags = e.packageJson?.startx?.gTags || [];
|
|
304
|
+
gTags.forEach(tag => appTags.add(tag));
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
return {
|
|
308
|
+
tags: Array.from(appTags),
|
|
309
|
+
selectedPackages: Array.from(packages.values()),
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
private static async installPackage(props: {
|
|
314
|
+
packages: PackageWithJson;
|
|
315
|
+
directory: {
|
|
316
|
+
workspace: string;
|
|
317
|
+
template: string;
|
|
318
|
+
};
|
|
319
|
+
tags: TAGS[];
|
|
320
|
+
dependencies: Record<string, string>;
|
|
321
|
+
}) {
|
|
322
|
+
const tags = new Set(props.tags.concat(props.packages.packageJson?.startx?.tags || []));
|
|
323
|
+
const { packageJson, isWorkspace } = FileHandler.handlePackageJson({
|
|
324
|
+
app: props.packages.packageJson!,
|
|
325
|
+
tags: Array.from(tags),
|
|
326
|
+
name: props.packages.name,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
if (isWorkspace) throw new Error("Can't install workspace as package.");
|
|
330
|
+
|
|
331
|
+
let iDirectory = path.join(props.directory.workspace, props.packages.type);
|
|
332
|
+
let iTemplate = path.join(props.directory.template, props.packages.type);
|
|
333
|
+
if (props.packages.packageJson?.name?.startsWith("@repo")) {
|
|
334
|
+
const repoName = props.packages.packageJson.name.split("/")[1];
|
|
335
|
+
iDirectory = path.join(iDirectory, "@repo", repoName);
|
|
336
|
+
iTemplate = path.join(iTemplate, "@repo", repoName);
|
|
337
|
+
} else {
|
|
338
|
+
iDirectory = path.join(iDirectory, props.packages.name);
|
|
339
|
+
iTemplate = path.join(iTemplate, props.packages.name);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
await fsTool.writeJSONFile({
|
|
343
|
+
dir: iDirectory,
|
|
344
|
+
file: "package",
|
|
345
|
+
content: packageJson,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
const files = await fsTool.listFiles({ dir: iTemplate });
|
|
349
|
+
for (const file of files) {
|
|
350
|
+
const checked = FileCheck[file];
|
|
351
|
+
if (checked && !checked.tags.every(e => props.tags.includes(e))) continue;
|
|
352
|
+
try {
|
|
353
|
+
await fsTool.copyFile({
|
|
354
|
+
from: path.join(iTemplate, file),
|
|
355
|
+
to: path.join(iDirectory, file),
|
|
356
|
+
});
|
|
357
|
+
} catch (error) {
|
|
358
|
+
logger.error(`Failed to copy file ${file}:`, error);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Installing src
|
|
363
|
+
await fsTool.copyDirectory({
|
|
364
|
+
from: path.join(iTemplate, "src"),
|
|
365
|
+
to: path.join(iDirectory, "src"),
|
|
366
|
+
exclude: !props.tags.includes("vitest") ? /\.test\.tsx?$/ : undefined,
|
|
367
|
+
});
|
|
368
|
+
logger.info(`Successfully installed ${props.packages.name}`);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
private static async installWorkspace(props: {
|
|
372
|
+
name: string;
|
|
373
|
+
tags: TAGS[];
|
|
374
|
+
dir: {
|
|
375
|
+
workspace: string;
|
|
376
|
+
template: string;
|
|
377
|
+
};
|
|
378
|
+
}) {
|
|
379
|
+
const rootTags = ["root", ...props.tags] as TAGS[];
|
|
380
|
+
const rawPackage = await CliUtils.parsePackageJson({ dir: props.dir.template });
|
|
381
|
+
const startXRawPackage = await CliUtils.parsePackageJson({
|
|
382
|
+
dir: props.dir.template,
|
|
383
|
+
file: "startx",
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
if (!rawPackage) throw new Error("Failed to parse package.json");
|
|
387
|
+
rawPackage.dependencies = startXRawPackage?.dependencies || {};
|
|
388
|
+
rawPackage.devDependencies = startXRawPackage?.devDependencies || {};
|
|
389
|
+
const { packageJson } = FileHandler.handlePackageJson({
|
|
390
|
+
app: rawPackage,
|
|
391
|
+
tags: rootTags,
|
|
392
|
+
name: props.name,
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
await fsTool.writeJSONFile({
|
|
396
|
+
dir: props.dir.workspace,
|
|
397
|
+
file: "package",
|
|
398
|
+
content: packageJson,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
const files = await fsTool.listFiles({ dir: props.dir.template });
|
|
402
|
+
for (const file of files) {
|
|
403
|
+
const checked = FileCheck[file];
|
|
404
|
+
if (checked && !checked.tags.every(e => rootTags.includes(e))) continue;
|
|
405
|
+
try {
|
|
406
|
+
await fsTool.copyFile({
|
|
407
|
+
from: path.join(props.dir.template, file),
|
|
408
|
+
to: path.join(props.dir.workspace, file),
|
|
409
|
+
});
|
|
410
|
+
} catch (error) {
|
|
411
|
+
logger.error(`Failed to copy file ${file}:`, error);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { WHITELIST_DEPS } from "../types";
|
|
2
|
+
|
|
3
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
4
|
+
export const DepCheck: WHITELIST_DEPS = {
|
|
5
|
+
"@biomejs/biome": {
|
|
6
|
+
tags: ["node", "biome", "root"],
|
|
7
|
+
version: "catalog:",
|
|
8
|
+
},
|
|
9
|
+
"prettier": {
|
|
10
|
+
tags: ["node", "prettier", "root"],
|
|
11
|
+
version: "catalog:",
|
|
12
|
+
},
|
|
13
|
+
"eslint": {
|
|
14
|
+
tags: ["node", "eslint", "root"],
|
|
15
|
+
version: "catalog:",
|
|
16
|
+
},
|
|
17
|
+
"vitest": {
|
|
18
|
+
tags: ["node", "vitest", "root"],
|
|
19
|
+
version: "catalog:",
|
|
20
|
+
},
|
|
21
|
+
"tsdown": {
|
|
22
|
+
tags: ["node", "tsdown", "root"],
|
|
23
|
+
version: "catalog:",
|
|
24
|
+
},
|
|
25
|
+
"@types/node": {
|
|
26
|
+
tags: ["node", "root"],
|
|
27
|
+
version: "catalog:",
|
|
28
|
+
isDevDependency: true,
|
|
29
|
+
},
|
|
30
|
+
"typescript-config": {
|
|
31
|
+
tags: ["node"],
|
|
32
|
+
version: "workspace:^",
|
|
33
|
+
isDevDependency: true,
|
|
34
|
+
},
|
|
35
|
+
"eslint-config": {
|
|
36
|
+
tags: ["node", "eslint"],
|
|
37
|
+
version: "workspace:^",
|
|
38
|
+
isDevDependency: true,
|
|
39
|
+
},
|
|
40
|
+
"vitest-config": {
|
|
41
|
+
tags: ["node", "vitest"],
|
|
42
|
+
version: "workspace:^",
|
|
43
|
+
isDevDependency: true,
|
|
44
|
+
},
|
|
45
|
+
} as const;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
2
|
+
import type { WHITELIST_FILES } from "../types";
|
|
3
|
+
|
|
4
|
+
export const FileCheck: WHITELIST_FILES = {
|
|
5
|
+
"startx.json": {
|
|
6
|
+
tags: ["never"],
|
|
7
|
+
},
|
|
8
|
+
".npmignore": {
|
|
9
|
+
tags: ["never"],
|
|
10
|
+
},
|
|
11
|
+
".npmrc": {
|
|
12
|
+
tags: ["never"],
|
|
13
|
+
},
|
|
14
|
+
".prettierignore": {
|
|
15
|
+
tags: ["prettier"],
|
|
16
|
+
},
|
|
17
|
+
".prettier.js": {
|
|
18
|
+
tags: ["prettier"],
|
|
19
|
+
},
|
|
20
|
+
"biome.json": {
|
|
21
|
+
tags: ["biome"],
|
|
22
|
+
},
|
|
23
|
+
"pnpm-lock.yaml": {
|
|
24
|
+
tags: ["never"],
|
|
25
|
+
},
|
|
26
|
+
"pnpm-workspace.yaml": {
|
|
27
|
+
tags: ["root"],
|
|
28
|
+
},
|
|
29
|
+
"turbo.json": {
|
|
30
|
+
tags: ["root"],
|
|
31
|
+
},
|
|
32
|
+
"LICENSE": {
|
|
33
|
+
tags: ["never"],
|
|
34
|
+
},
|
|
35
|
+
".env": {
|
|
36
|
+
tags: ["never"],
|
|
37
|
+
},
|
|
38
|
+
"tsdown.config.ts": {
|
|
39
|
+
tags: ["tsdown"],
|
|
40
|
+
},
|
|
41
|
+
// Handled manually
|
|
42
|
+
"eslint.config.ts": {
|
|
43
|
+
tags: ["never"],
|
|
44
|
+
},
|
|
45
|
+
"vitest.config.ts": {
|
|
46
|
+
tags: ["never"],
|
|
47
|
+
},
|
|
48
|
+
"package.json": {
|
|
49
|
+
tags: ["never"],
|
|
50
|
+
},
|
|
51
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
2
|
+
|
|
3
|
+
import type { SCRIPT } from "../types";
|
|
4
|
+
|
|
5
|
+
export const scripts: SCRIPT = {
|
|
6
|
+
"dev": [
|
|
7
|
+
{
|
|
8
|
+
script: "turbo run dev",
|
|
9
|
+
tags: ["runnable", "root"],
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
script: "tsx watch src/index.ts",
|
|
13
|
+
tags: ["runnable", "node", "backend", "dev"],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
script: "email dev --port 3014 --dir ./src",
|
|
17
|
+
tags: ["node", "mail"],
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
"dev:debug": [
|
|
21
|
+
{
|
|
22
|
+
script: "turbo run dev:debug",
|
|
23
|
+
tags: ["node", "runnable", "root"],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
script: "tsx watch --inspect src/index.ts",
|
|
27
|
+
tags: ["backend", "node", "runnable", "dev"],
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
"bun:dev": [
|
|
31
|
+
{
|
|
32
|
+
script: "turbo run bun:dev",
|
|
33
|
+
tags: ["node", "runnable", "root"],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
script: "bun --watch src/index.ts",
|
|
37
|
+
tags: ["backend", "node", "runnable", "dev"],
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
"build": [
|
|
41
|
+
{
|
|
42
|
+
script: "turbo run build",
|
|
43
|
+
tags: ["runnable", "root"],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
script: "tsdown --config-loader unrun",
|
|
47
|
+
tags: ["runnable", "node"],
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
"cli": [
|
|
51
|
+
{
|
|
52
|
+
script: "turbo run cli",
|
|
53
|
+
tags: ["runnable", "node", "cli", "root"],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
script: "tsx src/index.ts",
|
|
57
|
+
tags: ["runnable", "node", "cli", "commander"],
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
"start": [
|
|
61
|
+
{
|
|
62
|
+
script: "turbo run start",
|
|
63
|
+
tags: ["backend", "runnable", "node", "root"],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
script: "node dist/index.mjs",
|
|
67
|
+
tags: ["node", "runnable"],
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
"lint": [
|
|
71
|
+
{
|
|
72
|
+
script: "turbo run eslint",
|
|
73
|
+
tags: ["node", "eslint", "root"],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
script: "eslint .",
|
|
77
|
+
tags: ["node", "eslint"],
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
"lint:fix": [
|
|
81
|
+
{
|
|
82
|
+
script: "turbo run lint:fix",
|
|
83
|
+
tags: ["node", "eslint", "root"],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
script: "eslint . src/**/*.ts --fix",
|
|
87
|
+
tags: ["node", "eslint"],
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
"clean": [
|
|
91
|
+
{
|
|
92
|
+
script: "turbo run clean",
|
|
93
|
+
tags: ["root"],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
script: "rimraf dist .turbo dist",
|
|
97
|
+
tags: [],
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
"deep:clean": [
|
|
101
|
+
{
|
|
102
|
+
script: "turbo run deep:clean",
|
|
103
|
+
tags: ["root"],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
script: "rimraf node_modules dist .turbo",
|
|
107
|
+
tags: ["node"],
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
"typecheck": [
|
|
111
|
+
{
|
|
112
|
+
script: "turbo run typecheck",
|
|
113
|
+
tags: ["node", "root"],
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
script: "tsc --noEmit",
|
|
117
|
+
tags: ["node"],
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
"format": [
|
|
121
|
+
{
|
|
122
|
+
script: "turbo run format",
|
|
123
|
+
tags: ["node", "root"],
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
script: "biome format --write .",
|
|
127
|
+
tags: ["node", "biome", "prettier"],
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"script": "prettier --write .",
|
|
131
|
+
"tags": ["node", "prettier"],
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
"format:check": [
|
|
135
|
+
{
|
|
136
|
+
script: "turbo run format:check",
|
|
137
|
+
tags: ["node", "root"],
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
script: "biome ci .",
|
|
141
|
+
tags: ["node", "biome", "prettier"],
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"script": "prettier --check .",
|
|
145
|
+
"tags": ["node", "prettier"],
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
"test": [
|
|
149
|
+
{
|
|
150
|
+
script: "turbo run test",
|
|
151
|
+
tags: ["node", "vitest", "root"],
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
script: "vitest run",
|
|
155
|
+
tags: ["node", "vitest"],
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
} as const;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { logger } from "@repo/logger";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
|
|
5
|
+
import { InitCommand } from "./commands/init";
|
|
6
|
+
import { version } from "../../../package.json";
|
|
7
|
+
|
|
8
|
+
const program = new Command();
|
|
9
|
+
|
|
10
|
+
program
|
|
11
|
+
.name("startx")
|
|
12
|
+
.description("StartX CLI - Your all in one monorepo startup tool.")
|
|
13
|
+
.version(version);
|
|
14
|
+
|
|
15
|
+
program.command("ping").action(() => {
|
|
16
|
+
logger.info("pong");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
program.addCommand(InitCommand.command);
|
|
20
|
+
|
|
21
|
+
program.parse(process.argv);
|