@doki-land/nifty 0.0.0 → 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/src/cli/bump.ts CHANGED
@@ -1,237 +1,237 @@
1
- import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
-
4
- import { findWorkspaceRoot } from "./workspace.js";
5
-
6
- export type BumpKind = "patch" | "minor" | "major";
7
-
8
- export type BumpOptions = {
9
- /** Explicit target version. When set, overrides `kind`. */
10
- version?: string;
11
- kind?: BumpKind;
12
- cwd?: string;
13
- dryRun?: boolean;
14
- };
15
-
16
- export type BumpReport = {
17
- root: string;
18
- from: string;
19
- to: string;
20
- kind?: BumpKind;
21
- cargo: string[];
22
- npm: string[];
23
- };
24
-
25
- const DEFAULT_KIND: BumpKind = "patch";
26
-
27
- export async function runBump(argv: string[]): Promise<void> {
28
- const options = parseBumpArgs(argv);
29
- const report = bumpWorkspace(options);
30
- printReport(report, options.dryRun);
31
- }
32
-
33
- function parseBumpArgs(argv: string[]): BumpOptions {
34
- let version: string | undefined;
35
- let kind: BumpKind = DEFAULT_KIND;
36
- let cwd: string | undefined;
37
- let dryRun = false;
38
-
39
- for (let i = 0; i < argv.length; i += 1) {
40
- const arg = argv[i];
41
- if (arg === "--dry-run") {
42
- dryRun = true;
43
- } else if (arg === "-C" || arg === "--cwd") {
44
- cwd = argv[++i];
45
- } else if (arg === "--version" || arg === "-v") {
46
- version = argv[++i];
47
- } else if (arg === "--patch") {
48
- kind = "patch";
49
- } else if (arg === "--minor") {
50
- kind = "minor";
51
- } else if (arg === "--major") {
52
- kind = "major";
53
- } else if (arg === "-h" || arg === "--help") {
54
- printBumpHelp();
55
- process.exit(0);
56
- } else if (!arg.startsWith("-")) {
57
- if (isBumpKind(arg)) {
58
- kind = arg;
59
- } else {
60
- version = arg;
61
- }
62
- }
63
- }
64
-
65
- if (version) {
66
- assertVersion(version);
67
- }
68
- return { version, kind, cwd, dryRun };
69
- }
70
-
71
- function isBumpKind(value: string): value is BumpKind {
72
- return value === "patch" || value === "minor" || value === "major";
73
- }
74
-
75
- function assertVersion(version: string): void {
76
- if (!/^\d+\.\d+\.\d+(-[\w.-]+)?$/.test(version)) {
77
- throw new Error(`invalid version ${version}, expected semver like 0.0.0`);
78
- }
79
- }
80
-
81
- export function bumpWorkspace(options: BumpOptions): BumpReport {
82
- const root = findWorkspaceRoot(options.cwd ?? process.cwd());
83
- const cratesDir = join(root, "projects", "crates");
84
- const packagesDir = join(root, "projects", "packages");
85
-
86
- const cargoPaths = collectCargoManifests(cratesDir);
87
- const npmPaths = collectPackageManifests(packagesDir);
88
- const from = readWorkspaceVersion(cargoPaths, npmPaths);
89
- const to = options.version ?? bumpSemver(from, options.kind ?? DEFAULT_KIND);
90
- assertVersion(to);
91
-
92
- const cargo = cargoPaths.map((path) => bumpCargoManifest(path, to, options.dryRun));
93
- const npm = npmPaths.map((path) => bumpPackageManifest(path, to, options.dryRun));
94
-
95
- return {
96
- root,
97
- from,
98
- to,
99
- kind: options.version ? undefined : options.kind ?? DEFAULT_KIND,
100
- cargo,
101
- npm,
102
- };
103
- }
104
-
105
- function readWorkspaceVersion(cargoPaths: string[], npmPaths: string[]): string {
106
- const versions = new Set<string>();
107
- for (const path of cargoPaths) {
108
- versions.add(readCargoVersion(path));
109
- }
110
- for (const path of npmPaths) {
111
- versions.add(readPackageVersion(path));
112
- }
113
- if (versions.size === 0) {
114
- throw new Error("no crate or package versions found in workspace");
115
- }
116
- if (versions.size > 1) {
117
- throw new Error(`workspace versions are out of sync: ${[...versions].sort().join(", ")}`);
118
- }
119
- return [...versions][0];
120
- }
121
-
122
- function readCargoVersion(path: string): string {
123
- const original = readFileSync(path, "utf8");
124
- const match = original.match(/^version\s*=\s*"([^"]*)"/m);
125
- if (!match) {
126
- throw new Error(`no [package].version found in ${path}`);
127
- }
128
- return match[1];
129
- }
130
-
131
- function readPackageVersion(path: string): string {
132
- const parsed = JSON.parse(readFileSync(path, "utf8")) as { version?: string };
133
- if (!parsed.version) {
134
- throw new Error(`no version field in ${path}`);
135
- }
136
- return parsed.version;
137
- }
138
-
139
- export function bumpSemver(version: string, kind: BumpKind): string {
140
- const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-.*)?$/);
141
- if (!match) {
142
- throw new Error(`cannot bump non-semver version ${version}`);
143
- }
144
- let major = Number(match[1]);
145
- let minor = Number(match[2]);
146
- let patch = Number(match[3]);
147
-
148
- switch (kind) {
149
- case "patch":
150
- patch += 1;
151
- break;
152
- case "minor":
153
- minor += 1;
154
- patch = 0;
155
- break;
156
- case "major":
157
- major += 1;
158
- minor = 0;
159
- patch = 0;
160
- break;
161
- }
162
-
163
- return `${major}.${minor}.${patch}`;
164
- }
165
-
166
- function collectCargoManifests(cratesDir: string): string[] {
167
- if (!existsSync(cratesDir)) {
168
- return [];
169
- }
170
- return readdirSync(cratesDir, { withFileTypes: true })
171
- .filter((entry) => entry.isDirectory())
172
- .map((entry) => join(cratesDir, entry.name, "Cargo.toml"))
173
- .filter((path) => existsSync(path));
174
- }
175
-
176
- function collectPackageManifests(packagesDir: string): string[] {
177
- if (!existsSync(packagesDir)) {
178
- return [];
179
- }
180
- return readdirSync(packagesDir, { withFileTypes: true })
181
- .filter((entry) => entry.isDirectory() && entry.name !== "node_modules")
182
- .map((entry) => join(packagesDir, entry.name, "package.json"))
183
- .filter((path) => existsSync(path));
184
- }
185
-
186
- function bumpCargoManifest(path: string, version: string, dryRun?: boolean): string {
187
- const original = readFileSync(path, "utf8");
188
- const next = original.replace(/^version\s*=\s*"[^"]*"/m, `version = "${version}"`);
189
- if (next === original) {
190
- throw new Error(`no [package].version found in ${path}`);
191
- }
192
- if (!dryRun) {
193
- writeFileSync(path, next, "utf8");
194
- }
195
- return path;
196
- }
197
-
198
- function bumpPackageManifest(path: string, version: string, dryRun?: boolean): string {
199
- const original = readFileSync(path, "utf8");
200
- const parsed = JSON.parse(original) as { version?: string };
201
- if (!parsed.version) {
202
- throw new Error(`no version field in ${path}`);
203
- }
204
- parsed.version = version;
205
- const next = `${JSON.stringify(parsed, null, 4)}\n`;
206
- if (!dryRun) {
207
- writeFileSync(path, next, "utf8");
208
- }
209
- return path;
210
- }
211
-
212
- function printReport(report: BumpReport, dryRun?: boolean): void {
213
- const prefix = dryRun ? "would bump" : "bumped";
214
- const kind = report.kind ? ` (${report.kind})` : "";
215
- console.log(`${prefix} workspace ${report.root} ${report.from} -> ${report.to}${kind}`);
216
- for (const path of report.cargo) {
217
- console.log(` cargo: ${path}`);
218
- }
219
- for (const path of report.npm) {
220
- console.log(` npm: ${path}`);
221
- }
222
- }
223
-
224
- function printBumpHelp(): void {
225
- console.log(`nifty bump — align all crate and package versions in the workspace
226
-
227
- Usage:
228
- nifty bump # bump patch (default)
229
- nifty bump patch
230
- nifty bump minor
231
- nifty bump major
232
- nifty bump 1.2.3 # set explicit version
233
- nifty bump --version 1.2.3
234
- nifty bump --dry-run
235
- nifty bump -C <cwd>
236
- `);
237
- }
1
+ import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import { findWorkspaceRoot } from "./workspace.js";
5
+
6
+ export type BumpKind = "patch" | "minor" | "major";
7
+
8
+ export type BumpOptions = {
9
+ /** Explicit target version. When set, overrides `kind`. */
10
+ version?: string;
11
+ kind?: BumpKind;
12
+ cwd?: string;
13
+ dryRun?: boolean;
14
+ };
15
+
16
+ export type BumpReport = {
17
+ root: string;
18
+ from: string;
19
+ to: string;
20
+ kind?: BumpKind;
21
+ cargo: string[];
22
+ npm: string[];
23
+ };
24
+
25
+ const DEFAULT_KIND: BumpKind = "patch";
26
+
27
+ export async function runBump(argv: string[]): Promise<void> {
28
+ const options = parseBumpArgs(argv);
29
+ const report = bumpWorkspace(options);
30
+ printBumpReport(report, options.dryRun);
31
+ }
32
+
33
+ function parseBumpArgs(argv: string[]): BumpOptions {
34
+ let version: string | undefined;
35
+ let kind: BumpKind = DEFAULT_KIND;
36
+ let cwd: string | undefined;
37
+ let dryRun = false;
38
+
39
+ for (let i = 0; i < argv.length; i += 1) {
40
+ const arg = argv[i];
41
+ if (arg === "--dry-run") {
42
+ dryRun = true;
43
+ } else if (arg === "-C" || arg === "--cwd") {
44
+ cwd = argv[++i];
45
+ } else if (arg === "--version" || arg === "-v") {
46
+ version = argv[++i];
47
+ } else if (arg === "--patch") {
48
+ kind = "patch";
49
+ } else if (arg === "--minor") {
50
+ kind = "minor";
51
+ } else if (arg === "--major") {
52
+ kind = "major";
53
+ } else if (arg === "-h" || arg === "--help") {
54
+ printBumpHelp();
55
+ process.exit(0);
56
+ } else if (!arg.startsWith("-")) {
57
+ if (isBumpKind(arg)) {
58
+ kind = arg;
59
+ } else {
60
+ version = arg;
61
+ }
62
+ }
63
+ }
64
+
65
+ if (version) {
66
+ assertVersion(version);
67
+ }
68
+ return { version, kind, cwd, dryRun };
69
+ }
70
+
71
+ function isBumpKind(value: string): value is BumpKind {
72
+ return value === "patch" || value === "minor" || value === "major";
73
+ }
74
+
75
+ function assertVersion(version: string): void {
76
+ if (!/^\d+\.\d+\.\d+(-[\w.-]+)?$/.test(version)) {
77
+ throw new Error(`invalid version ${version}, expected semver like 0.0.0`);
78
+ }
79
+ }
80
+
81
+ export function bumpWorkspace(options: BumpOptions): BumpReport {
82
+ const root = findWorkspaceRoot(options.cwd ?? process.cwd());
83
+ const cratesDir = join(root, "projects", "crates");
84
+ const packagesDir = join(root, "projects", "packages");
85
+
86
+ const cargoPaths = collectCargoManifests(cratesDir);
87
+ const npmPaths = collectPackageManifests(packagesDir);
88
+ const from = readWorkspaceVersion(cargoPaths, npmPaths);
89
+ const to = options.version ?? bumpSemver(from, options.kind ?? DEFAULT_KIND);
90
+ assertVersion(to);
91
+
92
+ const cargo = cargoPaths.map((path) => bumpCargoManifest(path, to, options.dryRun));
93
+ const npm = npmPaths.map((path) => bumpPackageManifest(path, to, options.dryRun));
94
+
95
+ return {
96
+ root,
97
+ from,
98
+ to,
99
+ kind: options.version ? undefined : options.kind ?? DEFAULT_KIND,
100
+ cargo,
101
+ npm,
102
+ };
103
+ }
104
+
105
+ function readWorkspaceVersion(cargoPaths: string[], npmPaths: string[]): string {
106
+ const versions = new Set<string>();
107
+ for (const path of cargoPaths) {
108
+ versions.add(readCargoVersion(path));
109
+ }
110
+ for (const path of npmPaths) {
111
+ versions.add(readPackageVersion(path));
112
+ }
113
+ if (versions.size === 0) {
114
+ throw new Error("no crate or package versions found in workspace");
115
+ }
116
+ if (versions.size > 1) {
117
+ throw new Error(`workspace versions are out of sync: ${[...versions].sort().join(", ")}`);
118
+ }
119
+ return [...versions][0];
120
+ }
121
+
122
+ function readCargoVersion(path: string): string {
123
+ const original = readFileSync(path, "utf8");
124
+ const match = original.match(/^version\s*=\s*"([^"]*)"/m);
125
+ if (!match) {
126
+ throw new Error(`no [package].version found in ${path}`);
127
+ }
128
+ return match[1];
129
+ }
130
+
131
+ function readPackageVersion(path: string): string {
132
+ const parsed = JSON.parse(readFileSync(path, "utf8")) as { version?: string };
133
+ if (!parsed.version) {
134
+ throw new Error(`no version field in ${path}`);
135
+ }
136
+ return parsed.version;
137
+ }
138
+
139
+ export function bumpSemver(version: string, kind: BumpKind): string {
140
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-.*)?$/);
141
+ if (!match) {
142
+ throw new Error(`cannot bump non-semver version ${version}`);
143
+ }
144
+ let major = Number(match[1]);
145
+ let minor = Number(match[2]);
146
+ let patch = Number(match[3]);
147
+
148
+ switch (kind) {
149
+ case "patch":
150
+ patch += 1;
151
+ break;
152
+ case "minor":
153
+ minor += 1;
154
+ patch = 0;
155
+ break;
156
+ case "major":
157
+ major += 1;
158
+ minor = 0;
159
+ patch = 0;
160
+ break;
161
+ }
162
+
163
+ return `${major}.${minor}.${patch}`;
164
+ }
165
+
166
+ function collectCargoManifests(cratesDir: string): string[] {
167
+ if (!existsSync(cratesDir)) {
168
+ return [];
169
+ }
170
+ return readdirSync(cratesDir, { withFileTypes: true })
171
+ .filter((entry) => entry.isDirectory())
172
+ .map((entry) => join(cratesDir, entry.name, "Cargo.toml"))
173
+ .filter((path) => existsSync(path));
174
+ }
175
+
176
+ function collectPackageManifests(packagesDir: string): string[] {
177
+ if (!existsSync(packagesDir)) {
178
+ return [];
179
+ }
180
+ return readdirSync(packagesDir, { withFileTypes: true })
181
+ .filter((entry) => entry.isDirectory() && entry.name !== "node_modules")
182
+ .map((entry) => join(packagesDir, entry.name, "package.json"))
183
+ .filter((path) => existsSync(path));
184
+ }
185
+
186
+ function bumpCargoManifest(path: string, version: string, dryRun?: boolean): string {
187
+ const original = readFileSync(path, "utf8");
188
+ const next = original.replace(/^version\s*=\s*"[^"]*"/m, `version = "${version}"`);
189
+ if (next === original) {
190
+ throw new Error(`no [package].version found in ${path}`);
191
+ }
192
+ if (!dryRun) {
193
+ writeFileSync(path, next, "utf8");
194
+ }
195
+ return path;
196
+ }
197
+
198
+ function bumpPackageManifest(path: string, version: string, dryRun?: boolean): string {
199
+ const original = readFileSync(path, "utf8");
200
+ const parsed = JSON.parse(original) as { version?: string };
201
+ if (!parsed.version) {
202
+ throw new Error(`no version field in ${path}`);
203
+ }
204
+ parsed.version = version;
205
+ const next = `${JSON.stringify(parsed, null, 4)}\n`;
206
+ if (!dryRun) {
207
+ writeFileSync(path, next, "utf8");
208
+ }
209
+ return path;
210
+ }
211
+
212
+ export function printBumpReport(report: BumpReport, dryRun?: boolean): void {
213
+ const prefix = dryRun ? "would bump" : "bumped";
214
+ const kind = report.kind ? ` (${report.kind})` : "";
215
+ console.log(`${prefix} workspace ${report.root} ${report.from} -> ${report.to}${kind}`);
216
+ for (const path of report.cargo) {
217
+ console.log(` cargo: ${path}`);
218
+ }
219
+ for (const path of report.npm) {
220
+ console.log(` npm: ${path}`);
221
+ }
222
+ }
223
+
224
+ function printBumpHelp(): void {
225
+ console.log(`nifty bump — align all crate and package versions in the workspace
226
+
227
+ Usage:
228
+ nifty bump # bump patch (default)
229
+ nifty bump patch
230
+ nifty bump minor
231
+ nifty bump major
232
+ nifty bump 1.2.3 # set explicit version
233
+ nifty bump --version 1.2.3
234
+ nifty bump --dry-run
235
+ nifty bump -C <cwd>
236
+ `);
237
+ }
package/src/cli/cli.ts ADDED
@@ -0,0 +1,39 @@
1
+ import { dirname, join } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+
4
+ import { createCli } from "@vmz/commander";
5
+
6
+ import { registerBumpCommand } from "./bump-cmd.js";
7
+ import { registerInstallNativeCommand } from "./install-native-cmd.js";
8
+ import { registerLintCommands } from "./lint-cmd.js";
9
+ import { registerPublishCommand } from "./publish-cmd.js";
10
+ import { registerTrustCommand } from "./trust-cmd.js";
11
+ import { registerUpdateCommand } from "./update-cmd.js";
12
+ import { registerUploadCommand } from "./upload-cmd.js";
13
+
14
+ function buildNiftyCli() {
15
+ const localesRoot = join(dirname(fileURLToPath(import.meta.url)), "../../locales");
16
+ const cli = createCli("nifty")
17
+ .locales(localesRoot)
18
+ .intro("cli.intro")
19
+ .option("-C, --cwd <dir>", "cli.opt.cwd");
20
+
21
+ registerUpdateCommand(cli);
22
+ registerLintCommands(cli);
23
+ registerUploadCommand(cli);
24
+ registerInstallNativeCommand(cli);
25
+ registerBumpCommand(cli);
26
+ registerPublishCommand(cli);
27
+ registerTrustCommand(cli);
28
+
29
+ return cli;
30
+ }
31
+
32
+ export async function runCli(argv: string[]): Promise<number> {
33
+ try {
34
+ return await buildNiftyCli().parse(argv);
35
+ } catch (error) {
36
+ console.error(`error: ${error instanceof Error ? error.message : String(error)}`);
37
+ return 1;
38
+ }
39
+ }
@@ -1,26 +1,36 @@
1
- import { resolve } from "node:path";
2
-
3
- import { loadConfig } from "../config/loadConfig.js";
4
-
5
- /** Parse shared CLI flags used across nifty commands. */
6
- export function parseCliContext(argv: string[]): { cwd: string; dryRun: boolean } {
7
- let cwd = process.cwd();
8
- let dryRun = false;
9
-
10
- for (let i = 0; i < argv.length; i += 1) {
11
- const arg = argv[i];
12
- if (arg === "--dry-run") {
13
- dryRun = true;
14
- } else if (arg === "-C" || arg === "--cwd") {
15
- cwd = resolve(argv[++i] ?? cwd);
16
- }
17
- }
18
-
19
- return { cwd, dryRun };
20
- }
21
-
22
- /** Ensure `nifty.config.*` exists before running a command (skip create on `--dry-run`). */
23
- export async function bootstrapNiftyConfig(argv: string[]): Promise<void> {
24
- const { cwd, dryRun } = parseCliContext(argv);
25
- await loadConfig({ cwd, createIfMissing: !dryRun });
26
- }
1
+ import { resolve } from "node:path";
2
+
3
+ import type { ParsedOptions } from "@vmz/commander";
4
+
5
+ import { loadConfig } from "../config/loadConfig.js";
6
+ import { cwdFrom } from "./options.js";
7
+
8
+ /** Parse shared CLI flags used across nifty commands. */
9
+ export function parseCliContext(argv: string[]): { cwd: string; dryRun: boolean } {
10
+ let cwd = process.cwd();
11
+ let dryRun = false;
12
+
13
+ for (let i = 0; i < argv.length; i += 1) {
14
+ const arg = argv[i];
15
+ if (arg === "--dry-run") {
16
+ dryRun = true;
17
+ } else if (arg === "-C" || arg === "--cwd") {
18
+ cwd = resolve(argv[++i] ?? cwd);
19
+ }
20
+ }
21
+
22
+ return { cwd, dryRun };
23
+ }
24
+
25
+ /** Ensure `nifty.config.*` exists before running a command (skip create on `--dry-run`). */
26
+ export async function bootstrapNiftyConfig(argv: string[]): Promise<void> {
27
+ const { cwd, dryRun } = parseCliContext(argv);
28
+ await loadConfig({ cwd, createIfMissing: !dryRun });
29
+ }
30
+
31
+ /** Commander action hook: load config from parsed global/command flags. */
32
+ export async function bootstrapFromOptions(options: ParsedOptions): Promise<void> {
33
+ const cwd = cwdFrom(options) ?? process.cwd();
34
+ const dryRun = options["dry-run"] === true;
35
+ await loadConfig({ cwd, createIfMissing: !dryRun });
36
+ }
package/src/cli/index.ts CHANGED
@@ -1,8 +1,9 @@
1
- export { runCli } from "./main.js";
2
- export { bumpSemver, bumpWorkspace, runBump, type BumpKind, type BumpOptions, type BumpReport } from "./bump.js";
3
- export { runPublish, type PublishOptions, type PublishReport } from "./publish.js";
4
- export { runTrust, type TrustReport } from "./trust.js";
5
- export { runUpdate } from "./update.js";
6
- export { runLint } from "./lint.js";
7
- export { runUpload } from "./upload.js";
8
- export { findWorkspaceRoot, listWorkspacePackages, type WorkspacePackage } from "./workspace.js";
1
+ export { runCli } from "./main.js";
2
+ export { bumpSemver, bumpWorkspace, runBump, type BumpKind, type BumpOptions, type BumpReport } from "./bump.js";
3
+ export { runPublish, type PublishOptions, type PublishReport } from "./publish.js";
4
+ export { runTrust, type TrustReport } from "./trust.js";
5
+ export { runUpdate } from "./update.js";
6
+ export { runLint } from "./lint.js";
7
+ export { runUpload } from "./upload.js";
8
+ export { installNativeFromOptions, type InstallNativeOptions } from "./install-native.js";
9
+ export { findWorkspaceRoot, listWorkspacePackages, type WorkspacePackage } from "./workspace.js";
@@ -0,0 +1,22 @@
1
+ import type { Cli, ParsedOptions } from "@vmz/commander";
2
+
3
+ import { installNativeFromOptions } from "./install-native.js";
4
+ import { cwdFrom, str } from "./options.js";
5
+
6
+ export function registerInstallNativeCommand(cli: Cli): void {
7
+ cli.command("install-native", "cli.cmd.install-native")
8
+ .option("--from <dir>", "cli.opt.from-artifacts")
9
+ .action(async (options) => cmdInstallNative(options));
10
+ }
11
+
12
+ export async function cmdInstallNative(options: ParsedOptions): Promise<number> {
13
+ const from =
14
+ str(options, "from") ??
15
+ process.env.NATIVE_ARTIFACT_ROOT ??
16
+ "native-artifacts";
17
+ installNativeFromOptions({
18
+ from,
19
+ cwd: cwdFrom(options),
20
+ });
21
+ return 0;
22
+ }