@vlandoss/run-run 0.6.2-git-74f39bb.0 → 0.6.2-git-a1181c2.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/dist/cli.usage.kdl +71 -0
- package/dist/config.d.mts +11 -0
- package/dist/config.mjs +6 -0
- package/dist/run.mjs +535 -0
- package/dist/tools/tsdown.d.mts +1 -0
- package/dist/tools/tsdown.mjs +2 -0
- package/package.json +6 -11
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// @generated by @usage-spec/commander from Commander.js metadata
|
|
2
|
+
name rr
|
|
3
|
+
bin rr
|
|
4
|
+
version "0.6.2-git-a1181c2.0"
|
|
5
|
+
usage "[options] <command...>"
|
|
6
|
+
flag --usage help="print KDL spec for this CLI (https://kdl.dev)"
|
|
7
|
+
cmd completion help="print shell completion script 🐚 (usage)" {
|
|
8
|
+
long_help "Prints a shell completion script for rr. Add to your shell rc file:\n\n bash: eval \"$(rr completion bash)\"\n zsh: eval \"$(rr completion zsh)\"\n fish: rr completion fish | source"
|
|
9
|
+
arg <shell> help="target shell" {
|
|
10
|
+
choices bash zsh fish
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
cmd build:lib help="build a ts library 🏗️ (tsdown)" {
|
|
14
|
+
long_help "Compiles TypeScript code into JavaScript and generates type declaration files, making it ready for distribution."
|
|
15
|
+
cmd doctor help="check if the underlying tool is working correctly"
|
|
16
|
+
}
|
|
17
|
+
cmd jsc help="check format and lint 🔍 (biome)" {
|
|
18
|
+
alias jscheck
|
|
19
|
+
long_help "Checks the code for formatting and linting issues, ensuring it adheres to the defined style and quality standards."
|
|
20
|
+
flag --fix help="try to fix issues automatically"
|
|
21
|
+
flag --fix-staged help="try to fix staged files only"
|
|
22
|
+
cmd doctor help="check if the underlying tool is working correctly"
|
|
23
|
+
}
|
|
24
|
+
cmd tsc help="check typescript errors 📐 (tsc)" {
|
|
25
|
+
alias tscheck
|
|
26
|
+
long_help "Checks the TypeScript code for type errors, ensuring that the code adheres to the defined type constraints and helps catch potential issues before runtime."
|
|
27
|
+
cmd doctor help="check if the underlying tool is working correctly"
|
|
28
|
+
}
|
|
29
|
+
cmd lint help="check & fix lint errors 🔍 (biome)" {
|
|
30
|
+
long_help "Checks the code for linting issues and optionally fixes them, ensuring it adheres to the defined quality standards."
|
|
31
|
+
flag "-c --check" help="check if the code is valid" default=#true
|
|
32
|
+
flag --fix help="try to fix all the code"
|
|
33
|
+
cmd doctor help="check if the underlying tool is working correctly"
|
|
34
|
+
}
|
|
35
|
+
cmd format help="check & fix format errors 🎨 (biome)" {
|
|
36
|
+
long_help "Checks the code for formatting issues and optionally fixes them, ensuring it adheres to the defined style standards."
|
|
37
|
+
flag --fix help="format all the code"
|
|
38
|
+
cmd doctor help="check if the underlying tool is working correctly"
|
|
39
|
+
}
|
|
40
|
+
cmd check help="run static checks 🔬 (run-run)" {
|
|
41
|
+
long_help "Runs static checks, including linting, formatting checks, and TypeScript type checking, to ensure code quality and correctness without executing the code."
|
|
42
|
+
}
|
|
43
|
+
cmd clean help="delete dirty files 🗑️ (rimraf)" {
|
|
44
|
+
long_help "Deletes generated files and folders such as 'dist', 'node_modules', and lock files to ensure a clean state."
|
|
45
|
+
flag --only-dist help="delete 'dist' folders only"
|
|
46
|
+
flag --dry-run help="outputs the paths that would be deleted"
|
|
47
|
+
}
|
|
48
|
+
cmd pkgs help="list affected packages 📦" {
|
|
49
|
+
long_help "Given a list of files, returns the list of affected packages. Useful to run commands only on affected packages."
|
|
50
|
+
flag --files help="list of files to check" var=#true {
|
|
51
|
+
arg <FILES>
|
|
52
|
+
}
|
|
53
|
+
flag --decorator help="type of decorator to use" {
|
|
54
|
+
arg <DECORATOR> {
|
|
55
|
+
choices turbo
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
cmd x help="run multiple rr subcommands concurrently" {
|
|
60
|
+
long_help "Run multiple rr subcommands concurrently (e.g. `rr x jsc tsc`)."
|
|
61
|
+
arg <cmds>… help="rr subcommands to execute concurrently" var=#true
|
|
62
|
+
}
|
|
63
|
+
cmd config help="display the current config 🛠️" {
|
|
64
|
+
long_help "Displays the current configuration settings, including their source file path if available."
|
|
65
|
+
}
|
|
66
|
+
cmd tools hide=#true subcommand_required=#true help="expose the internal tools 🛠️" {
|
|
67
|
+
cmd biome
|
|
68
|
+
cmd oxfmt
|
|
69
|
+
cmd oxlint
|
|
70
|
+
cmd tsdown
|
|
71
|
+
}
|
package/dist/config.mjs
ADDED
package/dist/run.mjs
ADDED
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { colorize, createPkg, createShellService, cwd, dirnameOf, isCI, palette, resolvePackageBin, run, text } from "@vlandoss/clibuddy";
|
|
3
|
+
import { Argument, Option, createCommand } from "commander";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import { lilconfig } from "lilconfig";
|
|
7
|
+
import { createLoggy } from "@vlandoss/loggy";
|
|
8
|
+
import { glob } from "glob";
|
|
9
|
+
import { rimraf } from "rimraf";
|
|
10
|
+
import memoize from "memoize";
|
|
11
|
+
import { generateToStdout } from "@usage-spec/commander";
|
|
12
|
+
//#region src/services/logger.ts
|
|
13
|
+
const logger = createLoggy({ namespace: "run-run" });
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/services/config.ts
|
|
16
|
+
const DEFAULT_CONFIG = { future: { oxc: false } };
|
|
17
|
+
var ConfigService = class {
|
|
18
|
+
#searcher;
|
|
19
|
+
constructor() {
|
|
20
|
+
this.#searcher = lilconfig("run-run", {
|
|
21
|
+
searchPlaces: ["run-run.config.ts", "run-run.config.mts"],
|
|
22
|
+
cache: true,
|
|
23
|
+
stopDir: os.homedir(),
|
|
24
|
+
loaders: {
|
|
25
|
+
".ts": (filepath) => import(filepath).then((mod) => mod.default),
|
|
26
|
+
".mts": (filepath) => import(filepath).then((mod) => mod.default)
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async load() {
|
|
31
|
+
const debug = logger.subdebug("load-config");
|
|
32
|
+
const searchResult = await this.#searcher.search();
|
|
33
|
+
if (!searchResult || searchResult?.isEmpty) {
|
|
34
|
+
debug("loaded default config: %O", DEFAULT_CONFIG);
|
|
35
|
+
return {
|
|
36
|
+
config: DEFAULT_CONFIG,
|
|
37
|
+
meta: {
|
|
38
|
+
isDefault: true,
|
|
39
|
+
filepath: void 0
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const config = searchResult.config;
|
|
44
|
+
debug("loaded config: %O", config);
|
|
45
|
+
debug("config file: %s", searchResult.filepath);
|
|
46
|
+
return {
|
|
47
|
+
config,
|
|
48
|
+
meta: {
|
|
49
|
+
isDefault: false,
|
|
50
|
+
filepath: searchResult.filepath
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/services/ctx.ts
|
|
57
|
+
async function createContext(binDir) {
|
|
58
|
+
const debug = logger.subdebug("create-context");
|
|
59
|
+
const binPath = fs.realpathSync(binDir);
|
|
60
|
+
debug("bin path:", binPath);
|
|
61
|
+
debug("process cwd:", process.cwd());
|
|
62
|
+
const [appPkg, binPkg] = await Promise.all([createPkg(cwd), createPkg(binPath)]);
|
|
63
|
+
if (!binPkg) throw new Error("Could not find bin package.json");
|
|
64
|
+
if (!appPkg) throw new Error("Could not find app package.json");
|
|
65
|
+
debug("app pkg info: %O", appPkg.info());
|
|
66
|
+
debug("bin pkg info: %O", binPkg.info());
|
|
67
|
+
const shell = createShellService();
|
|
68
|
+
debug("shell service options: %O", shell.options);
|
|
69
|
+
return {
|
|
70
|
+
appPkg,
|
|
71
|
+
binPkg,
|
|
72
|
+
shell,
|
|
73
|
+
config: await new ConfigService().load()
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/program/ui.ts
|
|
78
|
+
const CREDITS_TEXT = `\nAcknowledgment:
|
|
79
|
+
- kcd-scripts: for main inspiration
|
|
80
|
+
${palette.link("https://github.com/kentcdodds/kcd-scripts")}
|
|
81
|
+
|
|
82
|
+
- peruvian news: in honor to Run Run
|
|
83
|
+
${palette.link("https://es.wikipedia.org/wiki/Run_Run")}`;
|
|
84
|
+
const tsdownColor = colorize("#FF7E18");
|
|
85
|
+
const biomeColor = colorize("#61A5FA");
|
|
86
|
+
const oxlintColor = colorize("#32F3E9");
|
|
87
|
+
const oxfmtColor = colorize("#32F3E9");
|
|
88
|
+
const tscColor = colorize("#3178C6");
|
|
89
|
+
const rimrafColor = colorize("#7C7270");
|
|
90
|
+
const runRunColor = colorize("#E8722A");
|
|
91
|
+
const usageColor = colorize("#24C55E");
|
|
92
|
+
const TOOL_LABELS = {
|
|
93
|
+
TSDOWN: tsdownColor("tsdown"),
|
|
94
|
+
BIOME: biomeColor("biome"),
|
|
95
|
+
OXLINT: oxlintColor("oxlint"),
|
|
96
|
+
OXFMT: oxfmtColor("oxfmt"),
|
|
97
|
+
TSC: tscColor("tsc"),
|
|
98
|
+
RIMRAF: rimrafColor("rimraf"),
|
|
99
|
+
RUN_RUN: runRunColor("run-run"),
|
|
100
|
+
USAGE: usageColor("usage")
|
|
101
|
+
};
|
|
102
|
+
function getBannerText(version) {
|
|
103
|
+
return `
|
|
104
|
+
${runRunColor(`
|
|
105
|
+
██████╗ ██╗ ██╗███╗ ██╗ ██████╗ ██╗ ██╗███╗ ██╗
|
|
106
|
+
██╔══██╗██║ ██║████╗ ██║ ██╔══██╗██║ ██║████╗ ██║
|
|
107
|
+
██████╔╝██║ ██║██╔██╗ ██║█████╗██████╔╝██║ ██║██╔██╗ ██║
|
|
108
|
+
██╔══██╗██║ ██║██║╚██╗██║╚════╝██╔══██╗██║ ██║██║╚██╗██║
|
|
109
|
+
██║ ██║╚██████╔╝██║ ╚████║ ██║ ██║╚██████╔╝██║ ╚████║
|
|
110
|
+
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ${text.version(version)}
|
|
111
|
+
`.trim())}
|
|
112
|
+
|
|
113
|
+
🦊 ${palette.italic(palette.muted("The CLI toolbox for"))} ${text.vland}\n`.trimStart();
|
|
114
|
+
}
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/services/tool.ts
|
|
117
|
+
var ToolService = class {
|
|
118
|
+
#shellService;
|
|
119
|
+
#pkg;
|
|
120
|
+
#bin;
|
|
121
|
+
#ui;
|
|
122
|
+
get bin() {
|
|
123
|
+
return this.#bin;
|
|
124
|
+
}
|
|
125
|
+
get ui() {
|
|
126
|
+
return this.#ui;
|
|
127
|
+
}
|
|
128
|
+
get pkg() {
|
|
129
|
+
return this.#pkg;
|
|
130
|
+
}
|
|
131
|
+
constructor({ pkg, bin, ui, shellService }) {
|
|
132
|
+
this.#pkg = pkg;
|
|
133
|
+
this.#bin = bin ?? pkg;
|
|
134
|
+
this.#ui = ui;
|
|
135
|
+
this.#shellService = shellService;
|
|
136
|
+
}
|
|
137
|
+
async getBinDir() {
|
|
138
|
+
return resolvePackageBin(this.#pkg, {
|
|
139
|
+
from: import.meta.url,
|
|
140
|
+
binName: this.#bin
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
async exec(args = []) {
|
|
144
|
+
return this.#shellService.run(await this.getBinDir(), args, { display: this.#bin });
|
|
145
|
+
}
|
|
146
|
+
async doctor() {
|
|
147
|
+
const output = await this.#shellService.runCaptured(await this.getBinDir(), ["--help"], { throwOnError: false });
|
|
148
|
+
return {
|
|
149
|
+
ok: output.exitCode === 0,
|
|
150
|
+
output: {
|
|
151
|
+
stdout: output.stdout,
|
|
152
|
+
stderr: output.stderr,
|
|
153
|
+
exitCode: output.exitCode
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
//#endregion
|
|
159
|
+
//#region src/services/tsdown.ts
|
|
160
|
+
var TsdownService = class extends ToolService {
|
|
161
|
+
constructor(shellService) {
|
|
162
|
+
super({
|
|
163
|
+
pkg: "tsdown",
|
|
164
|
+
ui: TOOL_LABELS.TSDOWN,
|
|
165
|
+
shellService
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async buildLib() {
|
|
169
|
+
await this.exec();
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
//#endregion
|
|
173
|
+
//#region src/program/commands/doctor.ts
|
|
174
|
+
function createDoctorSubcommand(service) {
|
|
175
|
+
return createCommand("doctor").summary("check if the underlying tool is working correctly").action(async function doctorAction() {
|
|
176
|
+
const debug = logger.subdebug("doctor");
|
|
177
|
+
const { ok, output } = await service.doctor();
|
|
178
|
+
if (ok) {
|
|
179
|
+
logger.success(`${service.ui} ok`);
|
|
180
|
+
debug("%O", output);
|
|
181
|
+
} else {
|
|
182
|
+
logger.error(`${service.ui} not working`);
|
|
183
|
+
debug("%O", output);
|
|
184
|
+
process.exit(output.exitCode ?? 1);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
//#region src/program/commands/build-lib.ts
|
|
190
|
+
function createBuildLibCommand(ctx) {
|
|
191
|
+
const tsdownService = new TsdownService(ctx.shell);
|
|
192
|
+
return createCommand("build:lib").summary(`build a ts library 🏗️ (${tsdownService.ui})`).description("Compiles TypeScript code into JavaScript and generates type declaration files, making it ready for distribution.").addCommand(createDoctorSubcommand(tsdownService)).action(async function buildAction() {
|
|
193
|
+
await tsdownService.buildLib();
|
|
194
|
+
}).addHelpText("afterAll", `\nUnder the hood, this command uses the ${tsdownService.ui} CLI to build the project.`);
|
|
195
|
+
}
|
|
196
|
+
//#endregion
|
|
197
|
+
//#region src/program/commands/check.ts
|
|
198
|
+
function createCheckCommand(ctx) {
|
|
199
|
+
return createCommand("check").summary(`run static checks 🔬 (${TOOL_LABELS.RUN_RUN})`).description("Runs static checks, including linting, formatting checks, and TypeScript type checking, to ensure code quality and correctness without executing the code.").action(async function checkAction() {
|
|
200
|
+
await ctx.shell.run("rr", [
|
|
201
|
+
"x",
|
|
202
|
+
"jscheck",
|
|
203
|
+
"tscheck"
|
|
204
|
+
]);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/program/commands/clean.ts
|
|
209
|
+
function createCleanCommand() {
|
|
210
|
+
return createCommand("clean").summary(`delete dirty files 🗑️ (${TOOL_LABELS.RIMRAF})`).description("Deletes generated files and folders such as 'dist', 'node_modules', and lock files to ensure a clean state.").option("--only-dist", "delete 'dist' folders only").option("--dry-run", "outputs the paths that would be deleted").action(async function cleanCommandAction(options) {
|
|
211
|
+
async function run(paths, globOptions) {
|
|
212
|
+
if (options.dryRun) {
|
|
213
|
+
const toDelete = await glob(paths, globOptions);
|
|
214
|
+
logger.info("Paths that would be deleted: %O", toDelete);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
logger.start("Clean started");
|
|
218
|
+
await rimraf(paths, { glob: globOptions });
|
|
219
|
+
logger.success("Clean completed");
|
|
220
|
+
}
|
|
221
|
+
const BUILD_PATHS = ["**/dist"];
|
|
222
|
+
const ALL_DIRTY_PATHS = [
|
|
223
|
+
"**/.turbo",
|
|
224
|
+
"**/node_modules",
|
|
225
|
+
"pnpm-lock.yaml",
|
|
226
|
+
"bun.lock",
|
|
227
|
+
...BUILD_PATHS
|
|
228
|
+
];
|
|
229
|
+
if (options.onlyDist) await run(BUILD_PATHS, {
|
|
230
|
+
cwd,
|
|
231
|
+
ignore: ["**/node_modules/**"]
|
|
232
|
+
});
|
|
233
|
+
else await run(ALL_DIRTY_PATHS, { cwd });
|
|
234
|
+
}).addHelpText("afterAll", `\nUnder the hood, this command uses ${TOOL_LABELS.RIMRAF} to delete dirty folders or files.`);
|
|
235
|
+
}
|
|
236
|
+
//#endregion
|
|
237
|
+
//#region src/program/commands/completion.ts
|
|
238
|
+
const SHELLS = [
|
|
239
|
+
"bash",
|
|
240
|
+
"zsh",
|
|
241
|
+
"fish"
|
|
242
|
+
];
|
|
243
|
+
function createCompletionCommand() {
|
|
244
|
+
return createCommand("completion").summary(`print shell completion script 🐚 (${TOOL_LABELS.USAGE})`).description(`Prints a shell completion script for rr. Add to your shell rc file:
|
|
245
|
+
|
|
246
|
+
bash: eval "$(rr completion bash)"
|
|
247
|
+
zsh: eval "$(rr completion zsh)"
|
|
248
|
+
fish: rr completion fish | source`).addArgument(new Argument("<shell>", `target shell`).choices(SHELLS)).addHelpText("afterAll", `\nUnder the hood, this command uses ${TOOL_LABELS.USAGE} (https://usage.jdx.dev).
|
|
249
|
+
Make sure to have it installed and available in your PATH.`);
|
|
250
|
+
}
|
|
251
|
+
//#endregion
|
|
252
|
+
//#region src/program/commands/config.ts
|
|
253
|
+
function createConfigCommand(ctx) {
|
|
254
|
+
return createCommand("config").summary("display the current config 🛠️").description("Displays the current configuration settings, including their source file path if available.").action(async function configAction() {
|
|
255
|
+
const { config, meta } = ctx.config;
|
|
256
|
+
console.log(palette.muted("Config:"));
|
|
257
|
+
console.log(config);
|
|
258
|
+
console.log(palette.muted(`Loaded from ${meta.filepath ? palette.link(meta.filepath) : "n/a"}`));
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/services/biome.ts
|
|
263
|
+
const COMMON_FLAGS = ["--colors=force", "--no-errors-on-unmatched"];
|
|
264
|
+
var BiomeService = class extends ToolService {
|
|
265
|
+
constructor(shellService) {
|
|
266
|
+
super({
|
|
267
|
+
pkg: "@biomejs/biome",
|
|
268
|
+
bin: "biome",
|
|
269
|
+
ui: TOOL_LABELS.BIOME,
|
|
270
|
+
shellService
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
async format(options) {
|
|
274
|
+
const args = ["format", ...COMMON_FLAGS];
|
|
275
|
+
if (options.fix) args.push("--fix");
|
|
276
|
+
await this.exec(args);
|
|
277
|
+
}
|
|
278
|
+
async lint(options) {
|
|
279
|
+
const args = [
|
|
280
|
+
"check",
|
|
281
|
+
...COMMON_FLAGS,
|
|
282
|
+
"--formatter-enabled=false"
|
|
283
|
+
];
|
|
284
|
+
if (options.fix) args.push("--fix", "--unsafe");
|
|
285
|
+
await this.exec(args);
|
|
286
|
+
}
|
|
287
|
+
async check(options) {
|
|
288
|
+
if (options.fix) await this.exec([
|
|
289
|
+
"check",
|
|
290
|
+
...COMMON_FLAGS,
|
|
291
|
+
"--fix"
|
|
292
|
+
]);
|
|
293
|
+
else if (options.fixStaged) await this.exec([
|
|
294
|
+
"check",
|
|
295
|
+
...COMMON_FLAGS,
|
|
296
|
+
"--fix",
|
|
297
|
+
"--staged"
|
|
298
|
+
]);
|
|
299
|
+
else await this.exec([isCI ? "ci" : "check", ...COMMON_FLAGS]);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
//#endregion
|
|
303
|
+
//#region src/services/oxfmt.ts
|
|
304
|
+
var OxfmtService = class extends ToolService {
|
|
305
|
+
constructor(shellService) {
|
|
306
|
+
super({
|
|
307
|
+
pkg: "oxfmt",
|
|
308
|
+
ui: TOOL_LABELS.OXFMT,
|
|
309
|
+
shellService
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
async format(options) {
|
|
313
|
+
await this.exec(["--no-error-on-unmatched-pattern", options.fix ? "--fix" : "--check"]);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/program/commands/format.ts
|
|
318
|
+
function getToolService$2(ctx) {
|
|
319
|
+
const { config } = ctx.config;
|
|
320
|
+
if (config.future?.oxc) return new OxfmtService(ctx.shell);
|
|
321
|
+
return new BiomeService(ctx.shell);
|
|
322
|
+
}
|
|
323
|
+
function createFormatCommand(ctx) {
|
|
324
|
+
const toolService = getToolService$2(ctx);
|
|
325
|
+
return createCommand("format").summary(`check & fix format errors 🎨 (${toolService.ui})`).description("Checks the code for formatting issues and optionally fixes them, ensuring it adheres to the defined style standards.").option("--fix", "format all the code").addCommand(createDoctorSubcommand(toolService)).action(async function formatAction(options) {
|
|
326
|
+
await toolService.format(options);
|
|
327
|
+
}).addHelpText("afterAll", `\nUnder the hood, this command uses the ${toolService.ui} CLI to format the code.`);
|
|
328
|
+
}
|
|
329
|
+
//#endregion
|
|
330
|
+
//#region src/program/commands/jscheck.ts
|
|
331
|
+
function createJsCheckCommand(ctx) {
|
|
332
|
+
const checkerService = new BiomeService(ctx.shell);
|
|
333
|
+
return createCommand("jsc").alias("jscheck").summary(`check format and lint 🔍 (${checkerService.ui})`).description("Checks the code for formatting and linting issues, ensuring it adheres to the defined style and quality standards.").option("--fix", "try to fix issues automatically").option("--fix-staged", "try to fix staged files only").addCommand(createDoctorSubcommand(checkerService)).action(async function checkAction(options) {
|
|
334
|
+
await checkerService.check(options);
|
|
335
|
+
}).addHelpText("afterAll", `\nUnder the hood, this command uses the ${checkerService.ui} CLI to check the code.`);
|
|
336
|
+
}
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/services/oxlint.ts
|
|
339
|
+
var OxlintService = class extends ToolService {
|
|
340
|
+
constructor(shellService) {
|
|
341
|
+
super({
|
|
342
|
+
pkg: "oxlint",
|
|
343
|
+
ui: TOOL_LABELS.OXLINT,
|
|
344
|
+
shellService
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
async lint(options) {
|
|
348
|
+
await this.exec(["--report-unused-disable-directives", options.fix ? "--fix" : "--check"]);
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
//#endregion
|
|
352
|
+
//#region src/program/commands/lint.ts
|
|
353
|
+
function getToolService$1(ctx) {
|
|
354
|
+
const { config } = ctx.config;
|
|
355
|
+
if (config.future?.oxc) return new OxlintService(ctx.shell);
|
|
356
|
+
return new BiomeService(ctx.shell);
|
|
357
|
+
}
|
|
358
|
+
function createLintCommand(ctx) {
|
|
359
|
+
const toolService = getToolService$1(ctx);
|
|
360
|
+
return createCommand("lint").summary(`check & fix lint errors 🔍 (${toolService.ui})`).description("Checks the code for linting issues and optionally fixes them, ensuring it adheres to the defined quality standards.").option("-c, --check", "check if the code is valid", true).option("--fix", "try to fix all the code").addCommand(createDoctorSubcommand(toolService)).action(async function lintAction(options) {
|
|
361
|
+
await toolService.lint(options);
|
|
362
|
+
}).addHelpText("afterAll", `\nUnder the hood, this command uses the ${toolService.ui} CLI to lint the code.`);
|
|
363
|
+
}
|
|
364
|
+
//#endregion
|
|
365
|
+
//#region src/program/commands/pkgs.ts
|
|
366
|
+
const decorators = ["turbo"];
|
|
367
|
+
function createPkgsCommand(ctx) {
|
|
368
|
+
return createCommand("pkgs").summary("list affected packages 📦").description("Given a list of files, returns the list of affected packages. Useful to run commands only on affected packages.").addOption(new Option("--files <files...>", "list of files to check")).addOption(new Option("--decorator [type]", "type of decorator to use").choices(decorators)).action(async function pkgsAction({ files, decorator }, cmd) {
|
|
369
|
+
const { appPkg } = ctx;
|
|
370
|
+
if (!appPkg.isMonorepo()) {
|
|
371
|
+
const cmdName = cmd.parent?.args[0] ?? cmd.args[0] ?? cmd.name();
|
|
372
|
+
logger.error(`The \`${cmdName}\` command can only be run in a monorepo.`);
|
|
373
|
+
return process.exit(1);
|
|
374
|
+
}
|
|
375
|
+
const projects = await appPkg.getWorkspaceProjects();
|
|
376
|
+
const getRelativeRootDir = memoize((rootDir) => {
|
|
377
|
+
const appDir = appPkg.dirPath;
|
|
378
|
+
if (!path.isAbsolute(rootDir)) return rootDir;
|
|
379
|
+
return path.relative(appDir, rootDir);
|
|
380
|
+
});
|
|
381
|
+
function getPackageForFile(filePath) {
|
|
382
|
+
for (const project of projects) {
|
|
383
|
+
const relativeRootDir = getRelativeRootDir(project.rootDir);
|
|
384
|
+
if (filePath.startsWith(relativeRootDir)) return project;
|
|
385
|
+
}
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
const uniquePkgsNames = /* @__PURE__ */ new Set();
|
|
389
|
+
files.forEach((file) => {
|
|
390
|
+
const pkg = getPackageForFile(file);
|
|
391
|
+
if (pkg?.manifest.name) uniquePkgsNames.add(pkg.manifest.name);
|
|
392
|
+
});
|
|
393
|
+
if (!uniquePkgsNames.size) return;
|
|
394
|
+
const pkgsNames = Array.from(uniquePkgsNames);
|
|
395
|
+
if (decorator === "turbo") console.log(...pkgsNames.map((name) => `--filter=...${name}`));
|
|
396
|
+
else console.log(...pkgsNames);
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
//#endregion
|
|
400
|
+
//#region src/program/commands/tools.ts
|
|
401
|
+
function getToolService(bin, shell) {
|
|
402
|
+
switch (bin) {
|
|
403
|
+
case "biome": return new BiomeService(shell);
|
|
404
|
+
case "oxfmt": return new OxfmtService(shell);
|
|
405
|
+
case "oxlint": return new OxlintService(shell);
|
|
406
|
+
case "tsdown": return new TsdownService(shell);
|
|
407
|
+
default: throw new Error(`Unknown tool: ${bin}`);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function createToolCommand(bin, shell) {
|
|
411
|
+
const tool = getToolService(bin, shell);
|
|
412
|
+
return createCommand(tool.bin).helpCommand(false).helpOption(false).allowExcessArguments(true).allowUnknownOption(true).action(async (_, { args }) => {
|
|
413
|
+
await tool.exec(args);
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
function createToolsCommand(ctx) {
|
|
417
|
+
return createCommand("tools").description("expose the internal tools 🛠️").passThroughOptions().addCommand(createToolCommand("biome", ctx.shell)).addCommand(createToolCommand("oxfmt", ctx.shell)).addCommand(createToolCommand("oxlint", ctx.shell)).addCommand(createToolCommand("tsdown", ctx.shell));
|
|
418
|
+
}
|
|
419
|
+
//#endregion
|
|
420
|
+
//#region src/services/tsc.ts
|
|
421
|
+
var TscService = class extends ToolService {
|
|
422
|
+
constructor(shellService) {
|
|
423
|
+
super({
|
|
424
|
+
pkg: "typescript",
|
|
425
|
+
bin: "tsc",
|
|
426
|
+
ui: TOOL_LABELS.TSC,
|
|
427
|
+
shellService
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
//#endregion
|
|
432
|
+
//#region src/program/commands/tscheck.ts
|
|
433
|
+
const getPreScript = (scripts) => scripts?.pretsc ?? scripts?.pretypecheck;
|
|
434
|
+
async function typecheckAt({ dir, scripts, log, shell, run }) {
|
|
435
|
+
let shellAt;
|
|
436
|
+
log.debug(`checking types at ${dir}`);
|
|
437
|
+
if (cwd === dir) shellAt = shell;
|
|
438
|
+
else {
|
|
439
|
+
log.debug(`Changing directory to ${dir} for typecheck`);
|
|
440
|
+
shellAt = shell.at(dir);
|
|
441
|
+
}
|
|
442
|
+
try {
|
|
443
|
+
const preScript = getPreScript(scripts);
|
|
444
|
+
if (preScript) {
|
|
445
|
+
log.start(`Running pre-script: ${preScript}`);
|
|
446
|
+
await shellAt.run(preScript, [], { shell: true });
|
|
447
|
+
log.success("Pre-script completed");
|
|
448
|
+
}
|
|
449
|
+
log.start("Type checking started");
|
|
450
|
+
await run(shellAt);
|
|
451
|
+
log.success("Typecheck completed");
|
|
452
|
+
} catch (error) {
|
|
453
|
+
log.error("Typecheck failed");
|
|
454
|
+
throw error;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
function createTsCheckCommand(ctx) {
|
|
458
|
+
const { appPkg, shell, config: { config } } = ctx;
|
|
459
|
+
const toolUi = config.future?.oxc ? TOOL_LABELS.OXLINT : TOOL_LABELS.TSC;
|
|
460
|
+
const doctorService = config.future?.oxc ? new OxlintService(shell) : new TscService(shell);
|
|
461
|
+
return createCommand("tsc").alias("tscheck").summary(`check typescript errors 📐 (${toolUi})`).description("Checks the TypeScript code for type errors, ensuring that the code adheres to the defined type constraints and helps catch potential issues before runtime.").addCommand(createDoctorSubcommand(doctorService)).addHelpText("afterAll", `\nUnder the hood, this command uses the ${toolUi} CLI to check the code.`).action(async function typecheckAction() {
|
|
462
|
+
const isTsProject = (dir) => appPkg.hasFile("tsconfig.json", dir);
|
|
463
|
+
const runTypecheck = async (shell) => {
|
|
464
|
+
if (config.future?.oxc) await new OxlintService(shell).exec([
|
|
465
|
+
"--type-aware",
|
|
466
|
+
"--type-check",
|
|
467
|
+
"--report-unused-disable-directives"
|
|
468
|
+
]);
|
|
469
|
+
else await new TscService(shell).exec(["--noEmit"]);
|
|
470
|
+
};
|
|
471
|
+
if (!appPkg.isMonorepo()) {
|
|
472
|
+
if (!isTsProject(appPkg.dirPath)) {
|
|
473
|
+
logger.info("No tsconfig.json found, skipping typecheck");
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
await typecheckAt({
|
|
477
|
+
shell,
|
|
478
|
+
run: runTypecheck,
|
|
479
|
+
dir: appPkg.dirPath,
|
|
480
|
+
scripts: appPkg.packageJson.scripts,
|
|
481
|
+
log: logger
|
|
482
|
+
});
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
const tsProjects = (await appPkg.getWorkspaceProjects()).filter((project) => isTsProject(project.rootDir));
|
|
486
|
+
if (!tsProjects.length) {
|
|
487
|
+
logger.warn("No ts projects found in the monorepo, skipping typecheck");
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
await Promise.all(tsProjects.map((p) => typecheckAt({
|
|
491
|
+
shell,
|
|
492
|
+
run: runTypecheck,
|
|
493
|
+
dir: p.rootDir,
|
|
494
|
+
scripts: p.manifest.scripts,
|
|
495
|
+
log: logger.child({
|
|
496
|
+
tag: p.manifest.name,
|
|
497
|
+
namespace: "typecheck"
|
|
498
|
+
})
|
|
499
|
+
})));
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
//#endregion
|
|
503
|
+
//#region src/program/commands/usage.ts
|
|
504
|
+
function addUsage(program) {
|
|
505
|
+
return program.addOption(new Option("--usage", "print KDL spec for this CLI (https://kdl.dev)")).on("option:usage", () => {
|
|
506
|
+
generateToStdout(program);
|
|
507
|
+
process.exit(0);
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
//#endregion
|
|
511
|
+
//#region src/program/commands/x.ts
|
|
512
|
+
function createXCommand(ctx) {
|
|
513
|
+
return createCommand("x").summary("run multiple rr subcommands concurrently").description("Run multiple rr subcommands concurrently (e.g. `rr x jsc tsc`).").argument("<cmds...>", "rr subcommands to execute concurrently").action(async function runXAction(cmds) {
|
|
514
|
+
if ((await Promise.allSettled(cmds.map((cmd) => ctx.shell.run("rr", [cmd])))).some((r) => r.status === "rejected")) process.exitCode = 1;
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
//#endregion
|
|
518
|
+
//#region src/program/index.ts
|
|
519
|
+
async function createProgram(options) {
|
|
520
|
+
const ctx = await createContext(options.binDir);
|
|
521
|
+
const version = ctx.binPkg.version;
|
|
522
|
+
return {
|
|
523
|
+
program: addUsage(createCommand("rr").usage("[options] <command...>").enablePositionalOptions().version(version, "-v, --version").addHelpText("before", getBannerText(version)).addHelpText("after", CREDITS_TEXT).addCommand(createCompletionCommand()).addCommand(createBuildLibCommand(ctx)).addCommand(createJsCheckCommand(ctx)).addCommand(createTsCheckCommand(ctx)).addCommand(createLintCommand(ctx)).addCommand(createFormatCommand(ctx)).addCommand(createCheckCommand(ctx)).addCommand(createCleanCommand()).addCommand(createPkgsCommand(ctx)).addCommand(createXCommand(ctx)).addCommand(createConfigCommand(ctx)).addCommand(createToolsCommand(ctx), { hidden: true })),
|
|
524
|
+
ctx
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
//#endregion
|
|
528
|
+
//#region src/run.ts
|
|
529
|
+
const BIN_DIR = path.dirname(dirnameOf(import.meta));
|
|
530
|
+
await run(async () => {
|
|
531
|
+
const { program } = await createProgram({ binDir: BIN_DIR });
|
|
532
|
+
await program.parseAsync(process.argv, { from: "node" });
|
|
533
|
+
}, logger);
|
|
534
|
+
//#endregion
|
|
535
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "tsdown";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vlandoss/run-run",
|
|
3
|
-
"version": "0.6.2-git-
|
|
3
|
+
"version": "0.6.2-git-a1181c2.0",
|
|
4
4
|
"description": "The CLI toolbox to fullstack common scripts in Variable Land",
|
|
5
5
|
"homepage": "https://github.com/variableland/dx/tree/main/packages/run-run#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -12,10 +12,7 @@
|
|
|
12
12
|
"directory": "packages/run-run"
|
|
13
13
|
},
|
|
14
14
|
"license": "MIT",
|
|
15
|
-
"author":
|
|
16
|
-
"name": "rcrd",
|
|
17
|
-
"email": "rcrd@variable.land"
|
|
18
|
-
},
|
|
15
|
+
"author": "rcrd <rcrd@variable.land>",
|
|
19
16
|
"type": "module",
|
|
20
17
|
"imports": {
|
|
21
18
|
"#src/*": "./src/*",
|
|
@@ -56,8 +53,6 @@
|
|
|
56
53
|
"dependencies": {
|
|
57
54
|
"@biomejs/biome": "2.4.4",
|
|
58
55
|
"@usage-spec/commander": "1.1.0",
|
|
59
|
-
"@vlandoss/clibuddy": "0.6.1-git-74f39bb.0",
|
|
60
|
-
"@vlandoss/loggy": "0.2.1-git-74f39bb.0",
|
|
61
56
|
"commander": "14.0.3",
|
|
62
57
|
"glob": "13.0.6",
|
|
63
58
|
"lilconfig": "3.1.3",
|
|
@@ -67,13 +62,13 @@
|
|
|
67
62
|
"oxlint-tsgolint": "0.15.0",
|
|
68
63
|
"rimraf": "6.1.3",
|
|
69
64
|
"tsdown": "0.22.0",
|
|
70
|
-
"typescript": "6.0.3"
|
|
65
|
+
"typescript": "6.0.3",
|
|
66
|
+
"@vlandoss/loggy": "0.2.1-git-a1181c2.0",
|
|
67
|
+
"@vlandoss/clibuddy": "0.6.1-git-a1181c2.0"
|
|
71
68
|
},
|
|
72
69
|
"devDependencies": {
|
|
73
70
|
"@vlandoss/tsdown-config": "^0.0.1"
|
|
74
71
|
},
|
|
75
|
-
"readme": "ERROR: No README data found!",
|
|
76
|
-
"_id": "@vlandoss/run-run@0.6.1",
|
|
77
72
|
"scripts": {
|
|
78
73
|
"build": "tsdown && pnpm build:kdl",
|
|
79
74
|
"build:kdl": "./bin --usage > dist/cli.usage.kdl",
|
|
@@ -82,4 +77,4 @@
|
|
|
82
77
|
"test:integration": "vitest run --project integration",
|
|
83
78
|
"test:types": "rr tsc"
|
|
84
79
|
}
|
|
85
|
-
}
|
|
80
|
+
}
|