tegami 1.0.0-beta.4 → 1.0.0-beta.5

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.
@@ -0,0 +1,292 @@
1
+ import { n as execFailure } from "./error-We7chQVJ.js";
2
+ import { n as WorkspacePackage } from "./graph-gThXu8Cz.js";
3
+ import { readFile, writeFile } from "node:fs/promises";
4
+ import { join, normalize } from "node:path";
5
+ import { x } from "tinyexec";
6
+ import * as semver$1 from "semver";
7
+ import z from "zod";
8
+ import initToml, { edit, parse as parse$1 } from "@rainbowatcher/toml-edit-js";
9
+ import { glob } from "tinyglobby";
10
+ //#region src/providers/cargo/schema.ts
11
+ const cargoDependencySchema = z.union([z.string(), z.object({
12
+ version: z.string(),
13
+ package: z.string().optional(),
14
+ path: z.string().optional()
15
+ })]);
16
+ const cargoTargetConfigSchema = z.object({
17
+ dependencies: z.record(z.string(), cargoDependencySchema).optional(),
18
+ "dev-dependencies": z.record(z.string(), cargoDependencySchema).optional(),
19
+ "build-dependencies": z.record(z.string(), cargoDependencySchema).optional()
20
+ });
21
+ const cargoPackageSchema = z.object({
22
+ name: z.string(),
23
+ version: z.string().optional(),
24
+ publish: z.boolean().optional()
25
+ });
26
+ const cargoWorkspaceSchema = z.object({
27
+ members: z.array(z.string()).optional(),
28
+ exclude: z.array(z.string()).optional(),
29
+ package: z.object({ version: z.string().optional() }).optional()
30
+ });
31
+ const cargoManifestSchema = z.object({
32
+ package: cargoPackageSchema,
33
+ workspace: cargoWorkspaceSchema.optional(),
34
+ dependencies: z.record(z.string(), cargoDependencySchema).optional(),
35
+ "dev-dependencies": z.record(z.string(), cargoDependencySchema).optional(),
36
+ "build-dependencies": z.record(z.string(), cargoDependencySchema).optional(),
37
+ target: z.record(z.string(), cargoTargetConfigSchema).optional()
38
+ });
39
+ //#endregion
40
+ //#region src/providers/cargo.ts
41
+ const DEP_FIELDS = [
42
+ "dependencies",
43
+ "dev-dependencies",
44
+ "build-dependencies"
45
+ ];
46
+ var CargoPackage = class extends WorkspacePackage {
47
+ path;
48
+ manifest;
49
+ content;
50
+ workspaceManifest;
51
+ manager = "cargo";
52
+ constructor(path, manifest, content, workspaceManifest) {
53
+ super();
54
+ this.path = path;
55
+ this.manifest = manifest;
56
+ this.content = content;
57
+ this.workspaceManifest = workspaceManifest;
58
+ }
59
+ get name() {
60
+ return this.packageInfo.name;
61
+ }
62
+ get version() {
63
+ return this.packageInfo.version ?? this.workspaceVersion;
64
+ }
65
+ setVersion(version) {
66
+ this.packageInfo.version = version;
67
+ this.patch("package.version", version);
68
+ }
69
+ async write() {
70
+ await writeFile(join(this.path, "Cargo.toml"), this.content + "\n");
71
+ }
72
+ patch(path, value) {
73
+ this.content = edit(this.content, path, value);
74
+ }
75
+ get packageInfo() {
76
+ return this.manifest.package;
77
+ }
78
+ get workspaceVersion() {
79
+ return this.workspaceManifest?.workspace?.package?.version;
80
+ }
81
+ };
82
+ function cargo({ updateLockFile = true, bumpDep: getBumpDepType } = {}) {
83
+ let active = false;
84
+ return {
85
+ name: "cargo",
86
+ enforce: "pre",
87
+ async init() {
88
+ await initToml();
89
+ },
90
+ async resolve() {
91
+ await discoverCargoPackages(this.cwd, (pkg) => this.graph.add(pkg));
92
+ active = this.graph.getPackages().some((pkg) => pkg instanceof CargoPackage);
93
+ },
94
+ initDraft(plan) {
95
+ if (!active) return;
96
+ plan.addPolicy(depsPolicy(this, getBumpDepType));
97
+ },
98
+ async publishPreflight({ pkg }) {
99
+ if (!(pkg instanceof CargoPackage)) return;
100
+ const wait = [];
101
+ for (const { table } of dependencyTables(pkg.manifest, "")) for (const [rawName, dep] of Object.entries(table)) {
102
+ if (!dep || typeof dep === "string" || !dep.path) continue;
103
+ const id = `cargo:${dep.package ?? rawName}`;
104
+ const linked = this.graph.get(id);
105
+ if (!linked || !(linked instanceof CargoPackage)) continue;
106
+ wait.push(id);
107
+ }
108
+ return {
109
+ shouldPublish: pkg.version !== void 0 && pkg.packageInfo.publish !== false,
110
+ wait
111
+ };
112
+ },
113
+ resolvePlanStatus({ plan }) {
114
+ return Array.from(plan.packages, async ([id, { preflight }]) => {
115
+ if (!preflight.shouldPublish) return;
116
+ const pkg = this.graph.get(id);
117
+ if (!(pkg instanceof CargoPackage) || !pkg.version) return;
118
+ if (!await isPackagePublished(pkg.name, pkg.version)) return "pending";
119
+ });
120
+ },
121
+ async publish({ pkg }) {
122
+ if (!(pkg instanceof CargoPackage)) return;
123
+ const result = await x("cargo", ["publish"], { nodeOptions: { cwd: pkg.path } });
124
+ if (result.exitCode !== 0) {
125
+ if (/already exists|already published/i.test(`${result.stdout}\n${result.stderr}`)) return { type: "skipped" };
126
+ return {
127
+ type: "failed",
128
+ error: execFailure(`Failed to publish ${pkg.name}@${pkg.version}.`, result).message
129
+ };
130
+ }
131
+ return { type: "published" };
132
+ },
133
+ async applyDraft(draft) {
134
+ if (!active) return;
135
+ const { graph } = this;
136
+ const writes = [];
137
+ for (const pkg of graph.getPackages()) {
138
+ if (!(pkg instanceof CargoPackage)) continue;
139
+ const bumped = draft.getPackageDraft(pkg.id)?.bumpVersion(pkg);
140
+ if (bumped) pkg.setVersion(bumped);
141
+ }
142
+ for (const pkg of graph.getPackages()) {
143
+ if (!(pkg instanceof CargoPackage)) continue;
144
+ for (const { table, path: tablePath } of dependencyTables(pkg.manifest, "")) for (const [rawName, rawSpec] of Object.entries(table)) {
145
+ const spec = parseSpec(rawSpec);
146
+ if (!spec || !semver$1.validRange(spec.version)) continue;
147
+ const packageName = spec.package ?? rawName;
148
+ const linked = graph.get(`cargo:${packageName}`);
149
+ if (!linked || !(linked instanceof CargoPackage)) continue;
150
+ if (!linked.version || semver$1.satisfies(linked.version, spec.version)) continue;
151
+ let updatedRange;
152
+ if (spec.version.startsWith("^")) updatedRange = `^${linked.version}`;
153
+ else if (spec.version.startsWith("~")) updatedRange = `~${linked.version}`;
154
+ else updatedRange = linked.version;
155
+ table[rawName] = spec.setVersion(updatedRange);
156
+ pkg.patch(typeof rawSpec === "string" ? `${tablePath}.${rawName}` : `${tablePath}.${rawName}.version`, updatedRange);
157
+ }
158
+ writes.push(pkg.write());
159
+ }
160
+ await Promise.all(writes);
161
+ },
162
+ async applyCliDraft() {
163
+ if (!active || !updateLockFile) return;
164
+ const result = await x("cargo", ["update", "--workspace"], { nodeOptions: { cwd: this.cwd } });
165
+ if (result.exitCode !== 0) throw execFailure("Failed to update Cargo lock file", result);
166
+ }
167
+ };
168
+ }
169
+ function depsPolicy({ graph }, getBumpDepType = ({ kind }) => {
170
+ switch (kind) {
171
+ case "dependencies": return "patch";
172
+ case "build-dependencies":
173
+ case "dev-dependencies": return false;
174
+ }
175
+ }) {
176
+ return {
177
+ id: "cargo:deps",
178
+ onUpdate({ pkg, packageDraft: plan }) {
179
+ if (!(pkg instanceof CargoPackage)) return;
180
+ const group = graph.getPackageGroup(pkg.id);
181
+ for (const dependent of graph.getPackages()) {
182
+ if (!(dependent instanceof CargoPackage)) continue;
183
+ for (const { table, kind } of dependencyTables(dependent.manifest, "")) for (const [rawName, rawSpec] of Object.entries(table)) {
184
+ const spec = parseSpec(rawSpec);
185
+ if (!spec || !semver$1.validRange(spec.version)) continue;
186
+ if (pkg.id !== `cargo:${spec.package ?? rawName}`) continue;
187
+ if (group?.options.syncBump && graph.getPackageGroup(dependent.id) === group) continue;
188
+ const bumped = plan.bumpVersion(pkg);
189
+ if (!bumped || semver$1.satisfies(bumped, spec.version)) continue;
190
+ const bumpType = getBumpDepType({
191
+ kind,
192
+ dependent,
193
+ name: pkg.name,
194
+ version: spec.version
195
+ });
196
+ if (bumpType === false) continue;
197
+ this.bumpPackage(dependent, {
198
+ type: bumpType,
199
+ reason: `update dependency "${rawName}"`
200
+ });
201
+ }
202
+ }
203
+ }
204
+ };
205
+ }
206
+ async function isPackagePublished(name, version) {
207
+ const response = await fetch(`https://crates.io/api/v1/crates/${encodeURIComponent(name)}/${version}`);
208
+ if (response.status === 200) return true;
209
+ if (response.status === 404) return false;
210
+ throw new Error(`Unable to validate ${name}@${version} against crates.io: ${await response.text()}`);
211
+ }
212
+ async function buildEntry(path) {
213
+ try {
214
+ const content = await readFile(join(path, "Cargo.toml"), "utf8");
215
+ return {
216
+ manifest: cargoManifestSchema.parse(parse$1(content)),
217
+ content,
218
+ path
219
+ };
220
+ } catch {
221
+ return;
222
+ }
223
+ }
224
+ async function discoverCargoPackages(cwd, add) {
225
+ const root = await buildEntry(cwd);
226
+ if (!root) return;
227
+ if (root.manifest.package?.name) add(new CargoPackage(cwd, root.manifest, root.content, root.manifest));
228
+ const workspace = root.manifest.workspace;
229
+ if (!workspace?.members) return;
230
+ const paths = await expandWorkspaceMembers(cwd, workspace.members, workspace.exclude);
231
+ const manifests = await Promise.all(paths.map(buildEntry));
232
+ for (const entry of manifests) if (entry?.manifest.package?.name) add(new CargoPackage(entry.path, entry.manifest, entry.content, root.manifest));
233
+ }
234
+ async function expandWorkspaceMembers(cwd, members, exclude = []) {
235
+ const paths = members.includes(".") ? [cwd] : [];
236
+ const patterns = members.filter((member) => member !== ".");
237
+ if (patterns.length > 0) paths.push(...await glob(patterns, {
238
+ absolute: true,
239
+ cwd,
240
+ ignore: ["**/target/**", ...exclude],
241
+ onlyDirectories: true,
242
+ onlyFiles: false
243
+ }));
244
+ return paths.map(normalize);
245
+ }
246
+ function dependencyTables(manifest, prefix) {
247
+ const tables = [];
248
+ for (const field of DEP_FIELDS) {
249
+ const table = manifest[field];
250
+ if (table) {
251
+ const path = prefix ? `${prefix}.${field}` : field;
252
+ tables.push({
253
+ kind: field,
254
+ table,
255
+ path
256
+ });
257
+ }
258
+ }
259
+ const target = manifest.target;
260
+ if (target) for (const [targetKey, targetConfig] of Object.entries(target)) {
261
+ const targetPath = prefix ? `${prefix}.target.${targetKey}` : `target.${targetKey}`;
262
+ for (const field of DEP_FIELDS) {
263
+ const table = targetConfig[field];
264
+ if (table) tables.push({
265
+ kind: field,
266
+ table,
267
+ path: `${targetPath}.${field}`
268
+ });
269
+ }
270
+ }
271
+ return tables;
272
+ }
273
+ function parseSpec(v) {
274
+ if (typeof v === "string") return {
275
+ version: v,
276
+ setVersion(version) {
277
+ return version;
278
+ }
279
+ };
280
+ return {
281
+ package: v.package,
282
+ version: v.version,
283
+ setVersion(version) {
284
+ return {
285
+ ...v,
286
+ version
287
+ };
288
+ }
289
+ };
290
+ }
291
+ //#endregion
292
+ export { cargo as n, CargoPackage as t };
@@ -1,4 +1,4 @@
1
- import { O as Draft, _ as PublishPlan, t as Awaitable, u as Tegami } from "../types-DKZsadC8.js";
1
+ import { O as Draft, _ as PublishPlan, t as Awaitable, u as Tegami } from "../types-C1rEqeM4.js";
2
2
 
3
3
  //#region src/cli/index.d.ts
4
4
  interface TegamiCLIOptions {
package/dist/cli/index.js CHANGED
@@ -349,10 +349,10 @@ function parseCommandArgs(command, args) {
349
349
  type: "boolean",
350
350
  short: "h"
351
351
  } };
352
- for (const option of command.options) optionConfig[option.name] = {
352
+ for (const option of command.options) optionConfig[option.name] = option.short ? {
353
353
  type: option.type,
354
354
  short: option.short
355
- };
355
+ } : { type: option.type };
356
356
  const parsed = parseArgs({
357
357
  args,
358
358
  options: optionConfig,
@@ -453,8 +453,14 @@ function registerCoreCommands(cli, tegami, options) {
453
453
  cli.command("", { description: "create changelog files interactively" }).action(async () => {
454
454
  await runChangelogTui(tegami);
455
455
  });
456
- cli.command("version", { description: "draft version changes and write the publish lock" }).action(async () => {
457
- await versionPackages(tegami, { cli: options });
456
+ cli.command("version", { description: "draft version changes and write the publish lock" }).option("no-checks", {
457
+ type: "boolean",
458
+ description: "skip checking whether the publish lock is still pending"
459
+ }).action(async ({ values }) => {
460
+ await versionPackages(tegami, {
461
+ cli: options,
462
+ noChecks: values["no-checks"]
463
+ });
458
464
  });
459
465
  cli.command("ci", { description: "version and publish packages" }).action(async () => {
460
466
  if (await versionPackages(tegami, { cli: options })) return;
@@ -499,7 +505,7 @@ async function versionPackages(tegami, options) {
499
505
  outro("No versions changed.");
500
506
  return false;
501
507
  }
502
- if (await tegami.publishStatus() === "pending") {
508
+ if (!options.noChecks && await tegami.publishStatus() === "pending") {
503
509
  note(`Publish lock at ${context.lockPath} is still pending. Publish it before applying a new draft.`);
504
510
  outro("Cannot apply.");
505
511
  return false;
@@ -1,4 +1,4 @@
1
- import { r as LogGenerator } from "../types-DKZsadC8.js";
1
+ import { r as LogGenerator } from "../types-C1rEqeM4.js";
2
2
 
3
3
  //#region src/generators/simple.d.ts
4
4
  declare function simpleGenerator(): LogGenerator;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as PackageDraft, D as WorkspacePackage, E as PackageGroup, O as Draft, T as PackageGraph, _ as PublishPlan, a as PublishPreflight, c as TegamiPluginOption, d as tegami, f as CommitChangelog, g as PublishOptions, h as PackagePublishResult, i as PackageOptions, k as DraftPolicy, l as GenerateChangelogOptions, m as PackagePublishPlan, n as GroupOptions, o as TegamiOptions, p as PublishLock, r as LogGenerator, s as TegamiPlugin, u as Tegami } from "./types-DKZsadC8.js";
2
- export { type CommitChangelog, type Draft, type DraftPolicy, GenerateChangelogOptions, type GroupOptions, type LogGenerator, type PackageDraft, type PackageGraph, type PackageGroup, type PackageOptions, type PackagePublishPlan, type PackagePublishResult, type PublishLock, type PublishOptions, type PublishPlan, type PublishPreflight, Tegami, type TegamiOptions, type TegamiPlugin, type TegamiPluginOption, type WorkspacePackage, tegami };
1
+ import { A as PackageDraft, D as WorkspacePackage, E as PackageGroup, O as Draft, T as PackageGraph, _ as PublishPlan, a as PublishPreflight, c as TegamiPluginOption, d as tegami, f as CommitChangelog, g as PublishOptions, h as PackagePublishResult, i as PackageOptions, j as BumpType, k as DraftPolicy, l as GenerateChangelogOptions, m as PackagePublishPlan, n as GroupOptions, o as TegamiOptions, p as PublishLock, r as LogGenerator, s as TegamiPlugin, u as Tegami, w as TegamiContext } from "./types-C1rEqeM4.js";
2
+ export { type BumpType, type CommitChangelog, type Draft, type DraftPolicy, GenerateChangelogOptions, type GroupOptions, type LogGenerator, type PackageDraft, PackageGraph, type PackageGroup, type PackageOptions, type PackagePublishPlan, type PackagePublishResult, type PublishLock, type PublishOptions, type PublishPlan, type PublishPreflight, Tegami, type TegamiContext, type TegamiOptions, type TegamiPlugin, type TegamiPluginOption, WorkspacePackage, tegami };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as generateFromCommits } from "./generate-BfYdNTFi.js";
2
2
  import { r as handlePluginError, s as somePromise } from "./error-We7chQVJ.js";
3
- import { t as PackageGraph } from "./graph-gThXu8Cz.js";
4
- import { cargo } from "./providers/cargo.js";
3
+ import { n as WorkspacePackage, t as PackageGraph } from "./graph-gThXu8Cz.js";
4
+ import { n as cargo } from "./cargo-hlZX2akE.js";
5
5
  import { n as npm } from "./npm-CMOyacwf.js";
6
6
  import { a as parseChangelogFile, i as parsePublishLock, n as createDraft, o as readChangelogEntries, r as packageStoreSchema, t as changelogStoreSchema } from "./draft-DtFyGxe8.js";
7
7
  import fs, { mkdir, rm, writeFile } from "node:fs/promises";
@@ -268,4 +268,4 @@ function tegami(options = {}) {
268
268
  };
269
269
  }
270
270
  //#endregion
271
- export { tegami };
271
+ export { PackageGraph, WorkspacePackage, tegami };
@@ -1,4 +1,4 @@
1
- import { s as TegamiPlugin } from "../types-DKZsadC8.js";
1
+ import { s as TegamiPlugin } from "../types-C1rEqeM4.js";
2
2
 
3
3
  //#region src/plugins/git.d.ts
4
4
  interface GitPluginOptions {
@@ -52,7 +52,20 @@ function git(options = {}) {
52
52
  async resolvePlanStatus({ plan }) {
53
53
  const pendingTags = getPendingTags(plan);
54
54
  return Array.from(pendingTags, async (tag) => {
55
- if (!await gitTagExists(this.cwd, tag)) return "pending";
55
+ if ((await x("git", [
56
+ "rev-parse",
57
+ "-q",
58
+ "--verify",
59
+ `refs/tags/${tag}`
60
+ ], { nodeOptions: { cwd: this.cwd } })).exitCode === 0) return;
61
+ if ((await x("git", [
62
+ "ls-remote",
63
+ "--exit-code",
64
+ "--tags",
65
+ "origin",
66
+ `refs/tags/${tag}`
67
+ ], { nodeOptions: { cwd: this.cwd } })).exitCode === 0) return;
68
+ return "pending";
56
69
  });
57
70
  },
58
71
  async afterPublishAll({ plan }) {
@@ -74,18 +87,13 @@ function git(options = {}) {
74
87
  "origin",
75
88
  ...createdTags
76
89
  ], { nodeOptions: { cwd } });
77
- if (gitOut.exitCode !== 0) throw execFailure(`Failed to push Git tags to origin: ${createdTags.join(", ")}`, gitOut);
90
+ if (gitOut.exitCode !== 0) {
91
+ if (/already exists/i.test(`${gitOut.stdout}\n${gitOut.stderr}`)) return;
92
+ throw execFailure(`Failed to push Git tags to origin: ${createdTags.join(", ")}`, gitOut);
93
+ }
78
94
  }
79
95
  }
80
96
  };
81
97
  }
82
- async function gitTagExists(cwd, tag) {
83
- return (await x("git", [
84
- "rev-parse",
85
- "-q",
86
- "--verify",
87
- `refs/tags/${tag}`
88
- ], { nodeOptions: { cwd } })).exitCode === 0;
89
- }
90
98
  //#endregion
91
99
  export { git };
@@ -1,4 +1,4 @@
1
- import { D as WorkspacePackage, O as Draft, _ as PublishPlan, s as TegamiPlugin, t as Awaitable, w as TegamiContext } from "../types-DKZsadC8.js";
1
+ import { D as WorkspacePackage, O as Draft, _ as PublishPlan, s as TegamiPlugin, t as Awaitable, w as TegamiContext } from "../types-C1rEqeM4.js";
2
2
  import { GitPluginOptions } from "./git.js";
3
3
 
4
4
  //#region src/plugins/github.d.ts
@@ -3,7 +3,7 @@ import { t as changelogFilename } from "../generate-BfYdNTFi.js";
3
3
  import { a as cached, n as execFailure, o as isCI } from "../error-We7chQVJ.js";
4
4
  import { n as createDraft, o as readChangelogEntries } from "../draft-DtFyGxe8.js";
5
5
  import { git } from "./git.js";
6
- import { n as createVersionRequestBody, r as hasGitChanges, t as commitVersionBranchChanges } from "../version-request-cFS0Suzd.js";
6
+ import { n as createVersionRequestBody, r as hasGitChanges, t as commitVersionBranchChanges } from "../version-request-DKvR3_xb.js";
7
7
  import { readFile, writeFile } from "node:fs/promises";
8
8
  import { basename, join, relative, resolve } from "node:path";
9
9
  import { x } from "tinyexec";
@@ -1,4 +1,4 @@
1
- import { D as WorkspacePackage, O as Draft, _ as PublishPlan, s as TegamiPlugin, t as Awaitable, w as TegamiContext } from "../types-DKZsadC8.js";
1
+ import { D as WorkspacePackage, O as Draft, _ as PublishPlan, s as TegamiPlugin, t as Awaitable, w as TegamiContext } from "../types-C1rEqeM4.js";
2
2
  import { GitPluginOptions } from "./git.js";
3
3
 
4
4
  //#region src/plugins/gitlab.d.ts
@@ -3,7 +3,7 @@ import { t as changelogFilename } from "../generate-BfYdNTFi.js";
3
3
  import { a as cached, n as execFailure, o as isCI } from "../error-We7chQVJ.js";
4
4
  import { n as createDraft, o as readChangelogEntries } from "../draft-DtFyGxe8.js";
5
5
  import { git } from "./git.js";
6
- import { n as createVersionRequestBody, r as hasGitChanges, t as commitVersionBranchChanges } from "../version-request-cFS0Suzd.js";
6
+ import { n as createVersionRequestBody, r as hasGitChanges, t as commitVersionBranchChanges } from "../version-request-DKvR3_xb.js";
7
7
  import { readFile, writeFile } from "node:fs/promises";
8
8
  import { basename, join, relative, resolve } from "node:path";
9
9
  import { x } from "tinyexec";
@@ -1,4 +1,4 @@
1
- import { D as WorkspacePackage, j as BumpType, s as TegamiPlugin } from "../types-DKZsadC8.js";
1
+ import { D as WorkspacePackage, j as BumpType, s as TegamiPlugin } from "../types-C1rEqeM4.js";
2
2
 
3
3
  //#region src/plugins/go.d.ts
4
4
  interface GoModFile {
@@ -1,2 +1,2 @@
1
- import { b as cargo, v as CargoPackage, y as CargoPluginOptions } from "../types-DKZsadC8.js";
1
+ import { b as cargo, v as CargoPackage, y as CargoPluginOptions } from "../types-C1rEqeM4.js";
2
2
  export { CargoPackage, CargoPluginOptions, cargo };
@@ -1,281 +1,2 @@
1
- import { i as isNodeError, n as execFailure } from "../error-We7chQVJ.js";
2
- import { n as WorkspacePackage } from "../graph-gThXu8Cz.js";
3
- import { readFile, writeFile } from "node:fs/promises";
4
- import { join, normalize } from "node:path";
5
- import { x } from "tinyexec";
6
- import * as semver$1 from "semver";
7
- import initToml, { edit, parse as parse$1 } from "@rainbowatcher/toml-edit-js";
8
- import { glob } from "tinyglobby";
9
- //#region src/providers/cargo.ts
10
- const DEP_FIELDS = [
11
- "dependencies",
12
- "dev-dependencies",
13
- "build-dependencies"
14
- ];
15
- var CargoPackage = class extends WorkspacePackage {
16
- path;
17
- manifest;
18
- content;
19
- workspaceManifest;
20
- manager = "cargo";
21
- constructor(path, manifest, content, workspaceManifest) {
22
- super();
23
- this.path = path;
24
- this.manifest = manifest;
25
- this.content = content;
26
- this.workspaceManifest = workspaceManifest;
27
- }
28
- get name() {
29
- return this.packageInfo.name;
30
- }
31
- get version() {
32
- return stringValue(this.packageInfo.version) ?? this.workspaceVersion;
33
- }
34
- setVersion(version) {
35
- this.packageInfo.version = version;
36
- this.patch("package.version", version);
37
- }
38
- async write() {
39
- await writeFile(join(this.path, "Cargo.toml"), this.content + "\n");
40
- }
41
- patch(path, value) {
42
- this.content = edit(this.content, path, value);
43
- }
44
- get packageInfo() {
45
- this.manifest.package ??= {};
46
- return this.manifest.package;
47
- }
48
- get workspaceVersion() {
49
- return stringValue(tableValue(tableValue(this.workspaceManifest?.workspace)?.package)?.version);
50
- }
51
- };
52
- function cargo({ updateLockFile = true, bumpDep: getBumpDepType } = {}) {
53
- let active = false;
54
- return {
55
- name: "cargo",
56
- enforce: "pre",
57
- async init() {
58
- await initToml();
59
- },
60
- async resolve() {
61
- await discoverCargoPackages(this.cwd, (pkg) => this.graph.add(pkg));
62
- active = this.graph.getPackages().some((pkg) => pkg instanceof CargoPackage);
63
- },
64
- initDraft(plan) {
65
- if (!active) return;
66
- plan.addPolicy(depsPolicy(this, getBumpDepType));
67
- },
68
- async publishPreflight({ pkg }) {
69
- if (!(pkg instanceof CargoPackage)) return;
70
- const wait = [];
71
- for (const { table } of dependencyTables(pkg.manifest, "")) for (const [rawName, rawSpec] of Object.entries(table)) {
72
- if (!isTableValue(rawSpec) || typeof rawSpec.path !== "string") continue;
73
- const id = `cargo:${stringValue(rawSpec.package) ?? rawName}`;
74
- const linked = this.graph.get(id);
75
- if (!linked || !(linked instanceof CargoPackage)) continue;
76
- wait.push(id);
77
- }
78
- return {
79
- shouldPublish: pkg.version !== void 0 && pkg.packageInfo.publish !== false,
80
- wait
81
- };
82
- },
83
- resolvePlanStatus({ plan }) {
84
- return Array.from(plan.packages, async ([id, { preflight }]) => {
85
- if (!preflight.shouldPublish) return;
86
- const pkg = this.graph.get(id);
87
- if (!(pkg instanceof CargoPackage) || !pkg.version) return;
88
- if (!await isPackagePublished(pkg.name, pkg.version)) return "pending";
89
- });
90
- },
91
- async publish({ pkg }) {
92
- if (!(pkg instanceof CargoPackage)) return;
93
- const result = await x("cargo", ["publish"], { nodeOptions: { cwd: pkg.path } });
94
- if (result.exitCode !== 0) {
95
- if (/already exists|already published/i.test(`${result.stdout}\n${result.stderr}`)) return { type: "skipped" };
96
- return {
97
- type: "failed",
98
- error: execFailure(`Failed to publish ${pkg.name}@${pkg.version}.`, result).message
99
- };
100
- }
101
- return { type: "published" };
102
- },
103
- async applyDraft(draft) {
104
- if (!active) return;
105
- const { graph } = this;
106
- const writes = [];
107
- for (const pkg of graph.getPackages()) {
108
- if (!(pkg instanceof CargoPackage)) continue;
109
- const bumped = draft.getPackageDraft(pkg.id)?.bumpVersion(pkg);
110
- if (bumped) pkg.setVersion(bumped);
111
- }
112
- for (const pkg of graph.getPackages()) {
113
- if (!(pkg instanceof CargoPackage)) continue;
114
- for (const { table, path: tablePath } of dependencyTables(pkg.manifest, "")) for (const [rawName, rawSpec] of Object.entries(table)) {
115
- const spec = parseSpec(rawSpec);
116
- if (!spec || !semver$1.validRange(spec.version)) continue;
117
- const packageName = spec.package ?? rawName;
118
- const linked = graph.get(`cargo:${packageName}`);
119
- if (!linked || !(linked instanceof CargoPackage)) continue;
120
- if (!linked.version || semver$1.satisfies(linked.version, spec.version)) continue;
121
- let updatedRange;
122
- if (spec.version.startsWith("^")) updatedRange = `^${linked.version}`;
123
- else if (spec.version.startsWith("~")) updatedRange = `~${linked.version}`;
124
- else updatedRange = linked.version;
125
- table[rawName] = spec.setVersion(updatedRange);
126
- pkg.patch(typeof rawSpec === "string" ? `${tablePath}.${rawName}` : `${tablePath}.${rawName}.version`, updatedRange);
127
- }
128
- writes.push(pkg.write());
129
- }
130
- await Promise.all(writes);
131
- },
132
- async applyCliDraft() {
133
- if (!active || !updateLockFile) return;
134
- const result = await x("cargo", ["update", "--workspace"], { nodeOptions: { cwd: this.cwd } });
135
- if (result.exitCode !== 0) throw execFailure("Failed to update Cargo lock file", result);
136
- }
137
- };
138
- }
139
- function depsPolicy({ graph }, getBumpDepType = ({ kind }) => {
140
- switch (kind) {
141
- case "dependencies": return "patch";
142
- case "build-dependencies":
143
- case "dev-dependencies": return false;
144
- }
145
- }) {
146
- return {
147
- id: "cargo:deps",
148
- onUpdate({ pkg, packageDraft: plan }) {
149
- if (!(pkg instanceof CargoPackage)) return;
150
- const group = graph.getPackageGroup(pkg.id);
151
- for (const dependent of graph.getPackages()) {
152
- if (!(dependent instanceof CargoPackage)) continue;
153
- for (const { table, kind } of dependencyTables(dependent.manifest, "")) for (const [rawName, rawSpec] of Object.entries(table)) {
154
- const spec = parseSpec(rawSpec);
155
- if (!spec || !semver$1.validRange(spec.version)) continue;
156
- if (pkg.id !== `cargo:${spec.package ?? rawName}`) continue;
157
- if (group?.options.syncBump && graph.getPackageGroup(dependent.id) === group) continue;
158
- const bumped = plan.bumpVersion(pkg);
159
- if (!bumped || semver$1.satisfies(bumped, spec.version)) continue;
160
- const bumpType = getBumpDepType({
161
- kind,
162
- dependent,
163
- name: pkg.name,
164
- version: spec.version
165
- });
166
- if (bumpType === false) continue;
167
- this.bumpPackage(dependent, {
168
- type: bumpType,
169
- reason: `update dependency "${rawName}"`
170
- });
171
- }
172
- }
173
- }
174
- };
175
- }
176
- async function isPackagePublished(name, version) {
177
- const response = await fetch(`https://crates.io/api/v1/crates/${encodeURIComponent(name)}/${version}`);
178
- if (response.status === 200) return true;
179
- if (response.status === 404) return false;
180
- throw new Error(`Unable to validate ${name}@${version} against crates.io: ${await response.text()}`);
181
- }
182
- async function discoverCargoPackages(cwd, add) {
183
- const root = await readCargoManifest(cwd).catch((error) => {
184
- if (isNodeError(error) && error.code === "ENOENT") return void 0;
185
- throw error;
186
- });
187
- if (!root) return;
188
- addCargoPackage(cwd, root.manifest, root.content, root.manifest, add);
189
- const workspace = tableValue(root.manifest.workspace);
190
- const members = workspace?.members;
191
- if (!workspace || !Array.isArray(members)) return;
192
- const exclude = Array.isArray(workspace.exclude) ? workspace.exclude.filter((member) => typeof member === "string") : [];
193
- const paths = await expandWorkspaceMembers(cwd, members.filter((member) => typeof member === "string"), exclude);
194
- const manifests = await Promise.all(paths.map((path) => readCargoManifest(path).then((manifest) => ({
195
- path,
196
- manifest
197
- })).catch(() => void 0)));
198
- for (const entry of manifests) if (entry) addCargoPackage(entry.path, entry.manifest.manifest, entry.manifest.content, root.manifest, add);
199
- }
200
- function addCargoPackage(path, manifest, content, workspaceManifest, add) {
201
- if (!tableValue(manifest.package)?.name) return;
202
- add(new CargoPackage(path, manifest, content, workspaceManifest));
203
- }
204
- async function expandWorkspaceMembers(cwd, members, exclude) {
205
- const paths = members.includes(".") ? [cwd] : [];
206
- const patterns = members.filter((member) => member !== ".");
207
- if (patterns.length > 0) paths.push(...await glob(patterns, {
208
- absolute: true,
209
- cwd,
210
- ignore: ["**/target/**", ...exclude],
211
- onlyDirectories: true,
212
- onlyFiles: false
213
- }));
214
- return paths.map(normalize);
215
- }
216
- function dependencyTables(manifest, prefix) {
217
- const tables = [];
218
- for (const field of DEP_FIELDS) {
219
- const table = tableValue(manifest[field]);
220
- if (table) {
221
- const path = prefix ? `${prefix}.${field}` : field;
222
- tables.push({
223
- kind: field,
224
- table,
225
- path
226
- });
227
- }
228
- }
229
- const target = tableValue(manifest.target);
230
- if (target) for (const [targetKey, targetConfig] of Object.entries(target)) {
231
- const targetTable = tableValue(targetConfig);
232
- if (!targetTable) continue;
233
- const targetPath = prefix ? `${prefix}.target.${targetKey}` : `target.${targetKey}`;
234
- for (const field of DEP_FIELDS) {
235
- const table = tableValue(targetTable[field]);
236
- if (table) tables.push({
237
- kind: field,
238
- table,
239
- path: `${targetPath}.${field}`
240
- });
241
- }
242
- }
243
- return tables;
244
- }
245
- function parseSpec(v) {
246
- if (typeof v === "string") return {
247
- version: v,
248
- setVersion(version) {
249
- return version;
250
- }
251
- };
252
- if (isTableValue(v)) return {
253
- package: stringValue(v.package),
254
- version: v.version,
255
- setVersion(version) {
256
- return {
257
- ...v,
258
- version
259
- };
260
- }
261
- };
262
- }
263
- async function readCargoManifest(path) {
264
- const content = await readFile(join(path, "Cargo.toml"), "utf8");
265
- return {
266
- manifest: parse$1(content),
267
- content
268
- };
269
- }
270
- function isTableValue(value) {
271
- return value !== null && typeof value === "object" && !Array.isArray(value);
272
- }
273
- function tableValue(value) {
274
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
275
- return value;
276
- }
277
- function stringValue(value) {
278
- return typeof value === "string" ? value : void 0;
279
- }
280
- //#endregion
1
+ import { n as cargo, t as CargoPackage } from "../cargo-hlZX2akE.js";
281
2
  export { CargoPackage, cargo };
@@ -1,2 +1,2 @@
1
- import { C as npm, S as NpmPluginOptions, x as NpmPackage } from "../types-DKZsadC8.js";
1
+ import { C as npm, S as NpmPluginOptions, x as NpmPackage } from "../types-C1rEqeM4.js";
2
2
  export { NpmPackage, NpmPluginOptions, npm };
@@ -258,25 +258,74 @@ declare function npm({
258
258
  bumpDep: getBumpDepType
259
259
  }?: NpmPluginOptions): TegamiPlugin;
260
260
  //#endregion
261
+ //#region src/providers/cargo/schema.d.ts
262
+ declare const cargoManifestSchema: z.ZodObject<{
263
+ package: z.ZodObject<{
264
+ name: z.ZodString;
265
+ version: z.ZodOptional<z.ZodString>;
266
+ publish: z.ZodOptional<z.ZodBoolean>;
267
+ }, z.core.$strip>;
268
+ workspace: z.ZodOptional<z.ZodObject<{
269
+ members: z.ZodOptional<z.ZodArray<z.ZodString>>;
270
+ exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
271
+ package: z.ZodOptional<z.ZodObject<{
272
+ version: z.ZodOptional<z.ZodString>;
273
+ }, z.core.$strip>>;
274
+ }, z.core.$strip>>;
275
+ dependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
276
+ version: z.ZodString;
277
+ package: z.ZodOptional<z.ZodString>;
278
+ path: z.ZodOptional<z.ZodString>;
279
+ }, z.core.$strip>]>>>;
280
+ "dev-dependencies": z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
281
+ version: z.ZodString;
282
+ package: z.ZodOptional<z.ZodString>;
283
+ path: z.ZodOptional<z.ZodString>;
284
+ }, z.core.$strip>]>>>;
285
+ "build-dependencies": z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
286
+ version: z.ZodString;
287
+ package: z.ZodOptional<z.ZodString>;
288
+ path: z.ZodOptional<z.ZodString>;
289
+ }, z.core.$strip>]>>>;
290
+ target: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
291
+ dependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
292
+ version: z.ZodString;
293
+ package: z.ZodOptional<z.ZodString>;
294
+ path: z.ZodOptional<z.ZodString>;
295
+ }, z.core.$strip>]>>>;
296
+ "dev-dependencies": z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
297
+ version: z.ZodString;
298
+ package: z.ZodOptional<z.ZodString>;
299
+ path: z.ZodOptional<z.ZodString>;
300
+ }, z.core.$strip>]>>>;
301
+ "build-dependencies": z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
302
+ version: z.ZodString;
303
+ package: z.ZodOptional<z.ZodString>;
304
+ path: z.ZodOptional<z.ZodString>;
305
+ }, z.core.$strip>]>>>;
306
+ }, z.core.$strip>>>;
307
+ }, z.core.$strip>;
308
+ type CargoManifest = z.infer<typeof cargoManifestSchema>;
309
+ //#endregion
261
310
  //#region src/providers/cargo.d.ts
262
- interface TomlTable {
263
- [key: string]: TomlValue;
264
- }
265
- type TomlValue = string | number | boolean | TomlTable | TomlValue[];
266
311
  declare const DEP_FIELDS: readonly ["dependencies", "dev-dependencies", "build-dependencies"];
267
312
  declare class CargoPackage extends WorkspacePackage {
268
313
  readonly path: string;
269
- readonly manifest: TomlTable;
314
+ readonly manifest: CargoManifest;
270
315
  private content;
271
316
  private readonly workspaceManifest?;
272
317
  readonly manager = "cargo";
273
- constructor(path: string, manifest: TomlTable, content: string, workspaceManifest?: TomlTable | undefined);
318
+ constructor(path: string, manifest: CargoManifest, content: string, workspaceManifest?: CargoManifest | undefined);
274
319
  get name(): string;
275
320
  get version(): string | undefined;
276
321
  setVersion(version: string): void;
277
322
  write(): Promise<void>;
278
323
  patch(path: string, value: unknown): void;
279
- get packageInfo(): TomlTable;
324
+ get packageInfo(): {
325
+ name: string;
326
+ version?: string | undefined;
327
+ publish?: boolean | undefined;
328
+ };
280
329
  private get workspaceVersion();
281
330
  }
282
331
  interface CargoPluginOptions {
@@ -0,0 +1,6 @@
1
+ import { Result } from "tinyexec";
2
+
3
+ //#region src/utils/error.d.ts
4
+ declare function execFailure(context: string, result: Awaited<Result>): Error;
5
+ //#endregion
6
+ export { execFailure };
@@ -0,0 +1,2 @@
1
+ import { n as execFailure } from "../error-We7chQVJ.js";
2
+ export { execFailure };
@@ -3,7 +3,9 @@ import { n as execFailure } from "./error-We7chQVJ.js";
3
3
  import { x } from "tinyexec";
4
4
  //#region src/utils/version-request.ts
5
5
  async function hasGitChanges(cwd) {
6
- return (await x("git", ["status", "--porcelain"], { nodeOptions: { cwd } })).stdout.trim().length > 0;
6
+ const result = await x("git", ["status", "--porcelain"], { nodeOptions: { cwd } });
7
+ if (result.exitCode !== 0) throw execFailure("Failed to check git status.", result);
8
+ return result.stdout.trim().length > 0;
7
9
  }
8
10
  async function commitVersionBranchChanges(cwd, branch, title) {
9
11
  const gitOptions = { nodeOptions: { cwd } };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tegami",
3
- "version": "1.0.0-beta.4",
3
+ "version": "1.0.0-beta.5",
4
4
  "description": "Utility for package versioning & publish",
5
5
  "license": "MIT",
6
6
  "author": "Fuma Nama",
@@ -22,6 +22,7 @@
22
22
  "./plugins/go": "./dist/plugins/go.js",
23
23
  "./providers/cargo": "./dist/providers/cargo.js",
24
24
  "./providers/npm": "./dist/providers/npm.js",
25
+ "./utils": "./dist/utils/index.js",
25
26
  "./package.json": "./package.json"
26
27
  },
27
28
  "publishConfig": {
@@ -30,7 +31,7 @@
30
31
  "dependencies": {
31
32
  "@clack/prompts": "^1.6.0",
32
33
  "@rainbowatcher/toml-edit-js": "^0.6.5",
33
- "js-yaml": "^5.1.0",
34
+ "js-yaml": "^5.2.0",
34
35
  "package-manager-detector": "^1.6.0",
35
36
  "semver": "^7.8.5",
36
37
  "tinyexec": "^1.2.4",
@@ -38,7 +39,7 @@
38
39
  "zod": "^4.4.3"
39
40
  },
40
41
  "devDependencies": {
41
- "@types/node": "^26.0.0",
42
+ "@types/node": "^26.0.1",
42
43
  "@types/semver": "^7.7.1",
43
44
  "tsdown": "^0.22.3",
44
45
  "typescript": "6.0.3",