@chanom/cli 0.0.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/dist/index.js +383 -0
- package/package.json +29 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { intro, log, multiselect, outro, select, spinner } from "@clack/prompts";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { spawnSync } from "node:child_process";
|
|
7
|
+
//#region src/utils/detect-pm.ts
|
|
8
|
+
const KNOWN_PMS = [
|
|
9
|
+
"pnpm",
|
|
10
|
+
"yarn",
|
|
11
|
+
"bun",
|
|
12
|
+
"npm"
|
|
13
|
+
];
|
|
14
|
+
function fromPkgJson(cwd) {
|
|
15
|
+
const pkgPath = join(cwd, "package.json");
|
|
16
|
+
if (!existsSync(pkgPath)) return void 0;
|
|
17
|
+
try {
|
|
18
|
+
const { packageManager } = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
19
|
+
if (!packageManager) return void 0;
|
|
20
|
+
const name = packageManager.split("@")[0];
|
|
21
|
+
return KNOWN_PMS.includes(name) ? name : void 0;
|
|
22
|
+
} catch {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function fromUserAgent() {
|
|
27
|
+
const agent = process.env["npm_config_user_agent"];
|
|
28
|
+
if (!agent) return void 0;
|
|
29
|
+
return KNOWN_PMS.find((pm) => agent.startsWith(pm));
|
|
30
|
+
}
|
|
31
|
+
function detectPm(cwd = process.cwd(), defaultPm = "pnpm") {
|
|
32
|
+
return fromPkgJson(cwd) ?? fromUserAgent() ?? defaultPm;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/utils/git.ts
|
|
36
|
+
function run(args, cwd) {
|
|
37
|
+
const { status, stdout, stderr } = spawnSync("git", args, {
|
|
38
|
+
stdio: "pipe",
|
|
39
|
+
cwd,
|
|
40
|
+
encoding: "utf-8"
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
ok: status === 0,
|
|
44
|
+
stdout: (stdout ?? "").trim(),
|
|
45
|
+
stderr: (stderr ?? "").trim()
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function isGitRepo(cwd = process.cwd()) {
|
|
49
|
+
return existsSync(join(cwd, ".git"));
|
|
50
|
+
}
|
|
51
|
+
function init(cwd) {
|
|
52
|
+
return run(["init"], cwd);
|
|
53
|
+
}
|
|
54
|
+
/** True if git has a usable author identity (committer.name + committer.email). */
|
|
55
|
+
function hasIdentity(cwd) {
|
|
56
|
+
return run(["var", "GIT_COMMITTER_IDENT"], cwd).ok;
|
|
57
|
+
}
|
|
58
|
+
/** Set a repo-local identity so commits succeed on a fresh repo without global config. */
|
|
59
|
+
function setLocalIdentity(cwd, name, email) {
|
|
60
|
+
run([
|
|
61
|
+
"config",
|
|
62
|
+
"user.name",
|
|
63
|
+
name
|
|
64
|
+
], cwd);
|
|
65
|
+
run([
|
|
66
|
+
"config",
|
|
67
|
+
"user.email",
|
|
68
|
+
email
|
|
69
|
+
], cwd);
|
|
70
|
+
}
|
|
71
|
+
function stageAll(cwd) {
|
|
72
|
+
return run(["add", "."], cwd);
|
|
73
|
+
}
|
|
74
|
+
/** True if there is anything staged to commit. */
|
|
75
|
+
function hasStagedChanges(cwd) {
|
|
76
|
+
return !run([
|
|
77
|
+
"diff",
|
|
78
|
+
"--cached",
|
|
79
|
+
"--quiet"
|
|
80
|
+
], cwd).ok;
|
|
81
|
+
}
|
|
82
|
+
function commit(cwd, message) {
|
|
83
|
+
return run([
|
|
84
|
+
"commit",
|
|
85
|
+
"-m",
|
|
86
|
+
message
|
|
87
|
+
], cwd);
|
|
88
|
+
}
|
|
89
|
+
function writeGitignore(cwd, contents = "node_modules\n") {
|
|
90
|
+
writeFileSync(join(cwd, ".gitignore"), contents, "utf-8");
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/utils/install.ts
|
|
94
|
+
function installDev(pm, cwd, ...packages) {
|
|
95
|
+
spawnSync(pm, [
|
|
96
|
+
"add",
|
|
97
|
+
"-D",
|
|
98
|
+
...packages
|
|
99
|
+
], {
|
|
100
|
+
stdio: "inherit",
|
|
101
|
+
cwd
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/utils/pkg.ts
|
|
106
|
+
function isEsm(pkg) {
|
|
107
|
+
return pkg.type === "module";
|
|
108
|
+
}
|
|
109
|
+
function readPkg(cwd) {
|
|
110
|
+
const pkgPath = join(cwd, "package.json");
|
|
111
|
+
return {
|
|
112
|
+
pkg: JSON.parse(readFileSync(pkgPath, "utf-8")),
|
|
113
|
+
pkgPath
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function isPackageInstalled(pkg, name) {
|
|
117
|
+
return name in (pkg.dependencies ?? {}) || name in (pkg.devDependencies ?? {});
|
|
118
|
+
}
|
|
119
|
+
//#endregion
|
|
120
|
+
//#region src/commands/add-commitlint/index.ts
|
|
121
|
+
function getPackages$7(pkg) {
|
|
122
|
+
const missing = [];
|
|
123
|
+
if (!isPackageInstalled(pkg, "@commitlint/cli")) missing.push("@commitlint/cli");
|
|
124
|
+
if (!isPackageInstalled(pkg, "@commitlint/config-conventional")) missing.push("@commitlint/config-conventional");
|
|
125
|
+
return missing;
|
|
126
|
+
}
|
|
127
|
+
function apply$7(cwd) {
|
|
128
|
+
writeFileSync(join(cwd, ".commitlintrc.json"), JSON.stringify({ extends: ["@commitlint/config-conventional"] }, null, 2) + "\n");
|
|
129
|
+
if (existsSync(join(cwd, ".husky"))) writeFileSync(join(cwd, ".husky", "commit-msg"), "npx --no -- commitlint --edit $1\n");
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/commands/add-eslint/index.ts
|
|
133
|
+
function getPackages$6(pkg) {
|
|
134
|
+
return isPackageInstalled(pkg, "eslint") ? [] : ["eslint"];
|
|
135
|
+
}
|
|
136
|
+
function apply$6(cwd, esm) {
|
|
137
|
+
writeFileSync(join(cwd, `eslint.config.${esm ? "ts" : "mts"}`), `export { default } from '@chanom/dev-config/eslint/config';\n`);
|
|
138
|
+
const { pkg, pkgPath } = readPkg(cwd);
|
|
139
|
+
pkg.scripts ??= {};
|
|
140
|
+
const missing = {};
|
|
141
|
+
if (!pkg.scripts["lint"]) missing["lint"] = "eslint .";
|
|
142
|
+
if (!pkg.scripts["lint:fix"]) missing["lint:fix"] = "eslint . --fix";
|
|
143
|
+
for (const [key, value] of Object.entries(missing)) pkg.scripts[key] = value;
|
|
144
|
+
const skipped = ["lint", "lint:fix"].filter((k) => !(k in missing));
|
|
145
|
+
for (const key of skipped) log.warn(`\`${key}\` script already exists in package.json - skipping`);
|
|
146
|
+
if (Object.keys(missing).length > 0) writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
147
|
+
}
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region src/commands/add-husky/index.ts
|
|
150
|
+
const PM_EXEC = {
|
|
151
|
+
pnpm: ["pnpm", "exec"],
|
|
152
|
+
npm: ["npx"],
|
|
153
|
+
yarn: ["yarn"],
|
|
154
|
+
bun: ["bunx"]
|
|
155
|
+
};
|
|
156
|
+
function getPackages$5(pkg) {
|
|
157
|
+
return isPackageInstalled(pkg, "husky") ? [] : ["husky"];
|
|
158
|
+
}
|
|
159
|
+
function apply$5(cwd, pm) {
|
|
160
|
+
const [cmd, ...args] = PM_EXEC[pm];
|
|
161
|
+
spawnSync(cmd, [
|
|
162
|
+
...args,
|
|
163
|
+
"husky",
|
|
164
|
+
"init"
|
|
165
|
+
], {
|
|
166
|
+
stdio: "inherit",
|
|
167
|
+
cwd
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region src/commands/add-knip/index.ts
|
|
172
|
+
function getPackages$4(pkg) {
|
|
173
|
+
return isPackageInstalled(pkg, "knip") ? [] : ["knip"];
|
|
174
|
+
}
|
|
175
|
+
function apply$4(cwd) {
|
|
176
|
+
writeFileSync(join(cwd, "knip.json"), JSON.stringify({ entry: ["src/index.ts"] }, null, 2) + "\n");
|
|
177
|
+
const { pkg, pkgPath } = readPkg(cwd);
|
|
178
|
+
pkg.scripts ??= {};
|
|
179
|
+
if (pkg.scripts["knip"]) log.warn("`knip` script already exists in package.json - skipping");
|
|
180
|
+
else {
|
|
181
|
+
pkg.scripts["knip"] = "knip";
|
|
182
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/commands/add-lint-staged/index.ts
|
|
187
|
+
function getPackages$3(pkg) {
|
|
188
|
+
return isPackageInstalled(pkg, "lint-staged") ? [] : ["lint-staged"];
|
|
189
|
+
}
|
|
190
|
+
function apply$3(cwd, linters = [], formatters = []) {
|
|
191
|
+
const config = {};
|
|
192
|
+
const jsGlob = "**/*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}";
|
|
193
|
+
if (linters.includes("oxlint")) {
|
|
194
|
+
config[jsGlob] ??= [];
|
|
195
|
+
config[jsGlob].push("oxlint --fix");
|
|
196
|
+
}
|
|
197
|
+
if (linters.includes("eslint")) {
|
|
198
|
+
config[jsGlob] ??= [];
|
|
199
|
+
config[jsGlob].push("eslint --fix");
|
|
200
|
+
}
|
|
201
|
+
if (formatters.includes("oxfmt")) {
|
|
202
|
+
config["*"] ??= [];
|
|
203
|
+
config["*"].push("oxfmt");
|
|
204
|
+
}
|
|
205
|
+
if (formatters.includes("prettier")) {
|
|
206
|
+
config["*"] ??= [];
|
|
207
|
+
config["*"].push("prettier --ignore-unknown --write");
|
|
208
|
+
}
|
|
209
|
+
writeFileSync(join(cwd, ".lintstagedrc.json"), JSON.stringify(config, null, 2) + "\n");
|
|
210
|
+
if (existsSync(join(cwd, ".husky"))) writeFileSync(join(cwd, ".husky", "pre-commit"), "lint-staged\n");
|
|
211
|
+
}
|
|
212
|
+
//#endregion
|
|
213
|
+
//#region src/commands/add-oxfmt/logic.ts
|
|
214
|
+
function getMissingScripts$1(scripts) {
|
|
215
|
+
const missing = {};
|
|
216
|
+
if (!scripts["format"]) missing["format"] = "oxfmt";
|
|
217
|
+
if (!scripts["format:check"]) missing["format:check"] = "oxfmt --check";
|
|
218
|
+
return missing;
|
|
219
|
+
}
|
|
220
|
+
//#endregion
|
|
221
|
+
//#region src/commands/add-oxfmt/index.ts
|
|
222
|
+
function getPackages$2(pkg) {
|
|
223
|
+
return isPackageInstalled(pkg, "oxfmt") ? [] : [`oxfmt@0.56.0`, "@chanom/dev-config"];
|
|
224
|
+
}
|
|
225
|
+
function apply$2(cwd, esm) {
|
|
226
|
+
writeFileSync(join(cwd, `oxfmt.config.${esm ? "ts" : "mts"}`), `export { default } from '@chanom/dev-config/oxfmt/config';\n`);
|
|
227
|
+
const { pkg, pkgPath } = readPkg(cwd);
|
|
228
|
+
pkg.scripts ??= {};
|
|
229
|
+
const missing = getMissingScripts$1(pkg.scripts);
|
|
230
|
+
for (const [key, value] of Object.entries(missing)) pkg.scripts[key] = value;
|
|
231
|
+
const skipped = ["format", "format:check"].filter((k) => !(k in missing));
|
|
232
|
+
for (const key of skipped) log.warn(`\`${key}\` script already exists in package.json - skipping`);
|
|
233
|
+
if (Object.keys(missing).length > 0) writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
234
|
+
}
|
|
235
|
+
//#endregion
|
|
236
|
+
//#region src/commands/add-oxlint/logic.ts
|
|
237
|
+
function getMissingScripts(scripts) {
|
|
238
|
+
const missing = {};
|
|
239
|
+
if (!scripts["lint"]) missing["lint"] = "oxlint";
|
|
240
|
+
if (!scripts["lint:fix"]) missing["lint:fix"] = "oxlint --fix";
|
|
241
|
+
return missing;
|
|
242
|
+
}
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/commands/add-oxlint/index.ts
|
|
245
|
+
function getPackages$1(pkg) {
|
|
246
|
+
return isPackageInstalled(pkg, "oxlint") ? [] : [`oxlint@1.71.0`, "@chanom/dev-config"];
|
|
247
|
+
}
|
|
248
|
+
function apply$1(cwd, esm) {
|
|
249
|
+
writeFileSync(join(cwd, `oxlint.config.${esm ? "ts" : "mts"}`), `export { default } from '@chanom/dev-config/oxlint/config';\n`);
|
|
250
|
+
const { pkg, pkgPath } = readPkg(cwd);
|
|
251
|
+
pkg.scripts ??= {};
|
|
252
|
+
const missing = getMissingScripts(pkg.scripts);
|
|
253
|
+
for (const [key, value] of Object.entries(missing)) pkg.scripts[key] = value;
|
|
254
|
+
const skipped = ["lint", "lint:fix"].filter((k) => !(k in missing));
|
|
255
|
+
for (const key of skipped) log.warn(`\`${key}\` script already exists in package.json - skipping`);
|
|
256
|
+
if (Object.keys(missing).length > 0) writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
257
|
+
}
|
|
258
|
+
//#endregion
|
|
259
|
+
//#region src/commands/add-prettier/index.ts
|
|
260
|
+
function getPackages(pkg) {
|
|
261
|
+
return isPackageInstalled(pkg, "prettier") ? [] : ["prettier"];
|
|
262
|
+
}
|
|
263
|
+
function apply(cwd) {
|
|
264
|
+
writeFileSync(join(cwd, ".prettierrc"), JSON.stringify({}, null, 2) + "\n");
|
|
265
|
+
const { pkg, pkgPath } = readPkg(cwd);
|
|
266
|
+
pkg.scripts ??= {};
|
|
267
|
+
const missing = {};
|
|
268
|
+
if (!pkg.scripts["format"]) missing["format"] = "prettier --write .";
|
|
269
|
+
if (!pkg.scripts["format:check"]) missing["format:check"] = "prettier --check .";
|
|
270
|
+
for (const [key, value] of Object.entries(missing)) pkg.scripts[key] = value;
|
|
271
|
+
const skipped = ["format", "format:check"].filter((k) => !(k in missing));
|
|
272
|
+
for (const key of skipped) log.warn(`\`${key}\` script already exists in package.json - skipping`);
|
|
273
|
+
if (Object.keys(missing).length > 0) writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
274
|
+
}
|
|
275
|
+
//#endregion
|
|
276
|
+
//#region src/commands/brew/index.ts
|
|
277
|
+
async function brew(cwd = process.cwd()) {
|
|
278
|
+
intro(pc.magenta("🧋 Chanom - Let's brew your project!"));
|
|
279
|
+
if (!isGitRepo(cwd)) {
|
|
280
|
+
const s = spinner();
|
|
281
|
+
s.start("Git not found, initializing repository...");
|
|
282
|
+
init(cwd);
|
|
283
|
+
writeGitignore(cwd);
|
|
284
|
+
s.stop("Git initialized");
|
|
285
|
+
}
|
|
286
|
+
const pm = detectPm(cwd);
|
|
287
|
+
const toppings = await multiselect({
|
|
288
|
+
message: "Which toppings would you like?",
|
|
289
|
+
options: [
|
|
290
|
+
{
|
|
291
|
+
value: "oxlint",
|
|
292
|
+
label: "oxlint",
|
|
293
|
+
hint: "fast Rust-based linter"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
value: "oxfmt",
|
|
297
|
+
label: "oxfmt",
|
|
298
|
+
hint: "fast Rust-based formatter"
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
value: "eslint",
|
|
302
|
+
label: "eslint",
|
|
303
|
+
hint: "stub config"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
value: "prettier",
|
|
307
|
+
label: "prettier",
|
|
308
|
+
hint: "stub config"
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
value: "knip",
|
|
312
|
+
label: "knip",
|
|
313
|
+
hint: "stub config"
|
|
314
|
+
}
|
|
315
|
+
],
|
|
316
|
+
required: false
|
|
317
|
+
});
|
|
318
|
+
if (typeof toppings === "symbol") process.exit(0);
|
|
319
|
+
const sweetness = await select({
|
|
320
|
+
message: "How sweet would you like it?",
|
|
321
|
+
options: [{
|
|
322
|
+
value: "light",
|
|
323
|
+
label: "light",
|
|
324
|
+
hint: "warn only, no blocking"
|
|
325
|
+
}, {
|
|
326
|
+
value: "medium",
|
|
327
|
+
label: "medium",
|
|
328
|
+
hint: "block on commit (husky + lint-staged + commitlint)"
|
|
329
|
+
}]
|
|
330
|
+
});
|
|
331
|
+
if (typeof sweetness === "symbol") process.exit(0);
|
|
332
|
+
const { pkg } = readPkg(cwd);
|
|
333
|
+
const esm = isEsm(pkg);
|
|
334
|
+
const packages = [];
|
|
335
|
+
if (toppings.includes("oxlint")) packages.push(...getPackages$1(pkg));
|
|
336
|
+
if (toppings.includes("oxfmt")) packages.push(...getPackages$2(pkg));
|
|
337
|
+
if (toppings.includes("eslint")) packages.push(...getPackages$6(pkg));
|
|
338
|
+
if (toppings.includes("prettier")) packages.push(...getPackages(pkg));
|
|
339
|
+
if (toppings.includes("knip")) packages.push(...getPackages$4(pkg));
|
|
340
|
+
if (sweetness === "medium") packages.push(...getPackages$5(pkg), ...getPackages$3(pkg), ...getPackages$7(pkg));
|
|
341
|
+
if (packages.length > 0) {
|
|
342
|
+
const s = spinner();
|
|
343
|
+
const uniquePackages = Array.from(new Set(packages));
|
|
344
|
+
s.start(`Installing ${uniquePackages.join(", ")}...`);
|
|
345
|
+
installDev(pm, cwd, ...uniquePackages);
|
|
346
|
+
s.stop("Packages installed");
|
|
347
|
+
}
|
|
348
|
+
if (toppings.includes("oxlint")) apply$1(cwd, esm);
|
|
349
|
+
if (toppings.includes("oxfmt")) apply$2(cwd, esm);
|
|
350
|
+
if (toppings.includes("eslint")) apply$6(cwd, esm);
|
|
351
|
+
if (toppings.includes("prettier")) apply(cwd);
|
|
352
|
+
if (toppings.includes("knip")) apply$4(cwd);
|
|
353
|
+
if (sweetness === "medium") {
|
|
354
|
+
apply$5(cwd, pm);
|
|
355
|
+
apply$3(cwd, toppings.filter((t) => ["oxlint", "eslint"].includes(t)), toppings.filter((t) => ["oxfmt", "prettier"].includes(t)));
|
|
356
|
+
apply$7(cwd);
|
|
357
|
+
}
|
|
358
|
+
const s2 = spinner();
|
|
359
|
+
s2.start("Committing changes...");
|
|
360
|
+
if (!hasIdentity(cwd)) setLocalIdentity(cwd, "Chanom", "chanom@local");
|
|
361
|
+
stageAll(cwd);
|
|
362
|
+
if (hasStagedChanges(cwd)) {
|
|
363
|
+
const result = commit(cwd, "chore: setup chanom configuration");
|
|
364
|
+
if (result.ok) s2.stop("Changes committed");
|
|
365
|
+
else {
|
|
366
|
+
s2.stop(pc.yellow("Could not commit changes automatically"));
|
|
367
|
+
const detail = result.stderr || result.stdout;
|
|
368
|
+
log.warn(`${detail ? detail + "\n" : ""}Your files are staged - commit them manually when ready.`);
|
|
369
|
+
}
|
|
370
|
+
} else s2.stop("Nothing to commit, skipping");
|
|
371
|
+
outro(pc.green(`Your Chanom with ${toppings.join(", ")} toppings and ${sweetness} sweetness is ready! Enjoy! 🧋`));
|
|
372
|
+
}
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region src/index.ts
|
|
375
|
+
const command = process.argv[2];
|
|
376
|
+
if (command === "brew") await brew();
|
|
377
|
+
else {
|
|
378
|
+
console.error(`Unknown command: ${command ?? "(none)"}`);
|
|
379
|
+
console.error("Usage: chanom brew");
|
|
380
|
+
process.exit(1);
|
|
381
|
+
}
|
|
382
|
+
//#endregion
|
|
383
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@chanom/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"keywords": [],
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"chanom": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@clack/prompts": "1.6.0",
|
|
15
|
+
"picocolors": "1.1.1"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@tsconfig/node-lts": "24.0.0",
|
|
19
|
+
"@tsconfig/node-ts": "23.6.4",
|
|
20
|
+
"@types/node": "26.0.1",
|
|
21
|
+
"tsdown": "0.22.3",
|
|
22
|
+
"typescript": "6.0.3",
|
|
23
|
+
"@chanom/dev-config": "0.0.2"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsdown",
|
|
27
|
+
"dev": "tsdown --watch"
|
|
28
|
+
}
|
|
29
|
+
}
|