tegami 0.2.1 → 1.0.0-beta.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.
@@ -1,334 +1,2 @@
1
- import { i as isNodeError, n as execFailure } from "../error-DNy8R5ue.js";
2
- import { n as packageManifestSchema, r as pnpmWorkspaceSchema } from "../schemas-BdUlXfSu.js";
3
- import { n as WorkspacePackage } from "../graph-DrzluXw8.js";
4
- import { readFile, writeFile } from "node:fs/promises";
5
- import path from "node:path";
6
- import { x } from "tinyexec";
7
- import * as semver from "semver";
8
- import z from "zod";
9
- import { load } from "js-yaml";
10
- import { glob } from "tinyglobby";
11
- import { detect } from "package-manager-detector";
12
- //#region src/providers/npm.ts
13
- const DEP_FIELDS = [
14
- "dependencies",
15
- "devDependencies",
16
- "peerDependencies",
17
- "optionalDependencies"
18
- ];
19
- var NpmPackage = class extends WorkspacePackage {
20
- path;
21
- manifest;
22
- manager = "npm";
23
- constructor(path, manifest) {
24
- super();
25
- this.path = path;
26
- this.manifest = manifest;
27
- }
28
- get name() {
29
- return this.manifest.name;
30
- }
31
- get version() {
32
- return this.manifest.version ?? "0.0.0";
33
- }
34
- async write() {
35
- await writeFile(path.join(this.path, "package.json"), `${JSON.stringify(this.manifest, null, 2)}\n`);
36
- }
37
- initDraft() {
38
- const defaults = super.initDraft();
39
- if (this.manifest.publishConfig?.tag) {
40
- defaults.npm ??= {};
41
- defaults.npm.distTag ??= this.manifest.publishConfig.tag;
42
- }
43
- return defaults;
44
- }
45
- };
46
- function parseDependencySpec(context, dependent, name, range) {
47
- const { graph } = context;
48
- if (range.startsWith("workspace:")) return {
49
- range: range.slice(10),
50
- linked: graph.get(`npm:${name}`),
51
- protocol: "workspace"
52
- };
53
- if (range.startsWith("file:")) {
54
- let target = path.resolve(dependent.path, range.slice(5));
55
- if (path.basename(target) === "package.json") target = path.dirname(target);
56
- return {
57
- protocol: "file",
58
- raw: range,
59
- linked: graph.getPackages().find((pkg) => pkg instanceof NpmPackage && pkg.path === target)
60
- };
61
- }
62
- if (range.startsWith("npm:")) {
63
- const spec = range.slice(4);
64
- const separator = spec.lastIndexOf("@");
65
- if (separator <= 0) return;
66
- const alias = spec.slice(0, separator);
67
- return {
68
- alias,
69
- linked: graph.get(`npm:${alias}`),
70
- range: spec.slice(separator + 1),
71
- protocol: "npm"
72
- };
73
- }
74
- return {
75
- linked: graph.get(`npm:${name}`),
76
- range
77
- };
78
- }
79
- function formatDependencySpec(spec) {
80
- if (spec.protocol === "workspace") return `workspace:${spec.range}`;
81
- if (spec.protocol === "file") return spec.raw;
82
- if (spec.protocol === "npm") return `npm:${spec.alias}@${spec.range}`;
83
- return spec.range;
84
- }
85
- const packageLockSchema = z.object({
86
- id: z.string(),
87
- distTag: z.string().optional()
88
- });
89
- function npm({ client: defaultClient, onBreakPeerDep = "set", updateLockFile = true, bumpDep: getBumpDepType = ({ kind }) => {
90
- switch (kind) {
91
- case "dependencies":
92
- case "optionalDependencies": return "patch";
93
- case "devDependencies": return false;
94
- case "peerDependencies":
95
- if (onBreakPeerDep === "ignore") return false;
96
- return "major";
97
- }
98
- } } = {}) {
99
- let active = false;
100
- let client;
101
- return {
102
- name: "npm",
103
- enforce: "pre",
104
- async init() {
105
- if (defaultClient) client = defaultClient;
106
- else client = (await detect({ cwd: this.cwd }))?.name ?? "npm";
107
- this.npm = { client };
108
- },
109
- async resolve() {
110
- await discoverNpmPackages(this.cwd, (pkg) => this.graph.add(pkg));
111
- active = this.graph.getPackages().some((pkg) => pkg instanceof NpmPackage);
112
- },
113
- async publishPreflight({ pkg }) {
114
- if (!(pkg instanceof NpmPackage)) return;
115
- return { publish: pkg.manifest.private !== true && !await isPackagePublished(pkg) };
116
- },
117
- initPublishLock({ lock, draft }) {
118
- for (const [id, pkg] of draft.getPackageDrafts()) {
119
- if (!pkg.npm) continue;
120
- lock.write("npm:packages", {
121
- id,
122
- distTag: pkg.npm.distTag
123
- });
124
- }
125
- },
126
- initPublishPlan({ lock, plan }) {
127
- let data;
128
- while (data = lock.read("npm:packages")) {
129
- const parsed = packageLockSchema.safeParse(data).data;
130
- if (!parsed) continue;
131
- const packagePlan = plan.packages.get(parsed.id);
132
- if (!packagePlan) continue;
133
- packagePlan.npm = { distTag: parsed.distTag };
134
- }
135
- },
136
- async publish({ pkg, plan }) {
137
- if (!(pkg instanceof NpmPackage)) return;
138
- return publish(client, pkg, plan.packages.get(pkg.id)?.npm?.distTag);
139
- },
140
- initDraft(plan) {
141
- if (!active) return;
142
- plan.addPolicy(depsPolicy(this, getBumpDepType));
143
- },
144
- async applyDraft(draft) {
145
- if (!active) return;
146
- const { graph } = this;
147
- const writes = [];
148
- for (const pkg of graph.getPackages()) {
149
- if (!(pkg instanceof NpmPackage)) continue;
150
- const plan = draft.getPackageDraft(pkg.id);
151
- if (plan) pkg.manifest.version = plan.bumpVersion(pkg);
152
- }
153
- for (const pkg of graph.getPackages()) {
154
- if (!(pkg instanceof NpmPackage)) continue;
155
- for (const field of DEP_FIELDS) {
156
- const dependencies = pkg.manifest[field];
157
- if (!dependencies) continue;
158
- for (const [k, v] of Object.entries(dependencies)) {
159
- const spec = parseDependencySpec(this, pkg, k, v);
160
- if (!spec?.linked || spec.protocol === "workspace" || spec.protocol === "file") continue;
161
- if (!semver.validRange(spec.range)) continue;
162
- if (semver.satisfies(spec.linked.version, spec.range)) continue;
163
- let updatedRange;
164
- const isPeer = field === "peerDependencies";
165
- if (isPeer && onBreakPeerDep === "ignore") continue;
166
- else if (isPeer && onBreakPeerDep === "set") updatedRange = spec.linked.version;
167
- else if (isPeer && onBreakPeerDep === "error") throw new Error(`[Tegami] the version of "${spec.linked.name}" is beyond its peer dependency constraint "${v}" in package "${pkg.name}", please update the constraint to satisfy.`);
168
- else if (spec.range.startsWith("^")) updatedRange = `^${spec.linked.version}`;
169
- else if (spec.range.startsWith("~")) updatedRange = `~${spec.linked.version}`;
170
- else updatedRange = spec.linked.version;
171
- dependencies[k] = formatDependencySpec({
172
- ...spec,
173
- range: updatedRange
174
- });
175
- }
176
- }
177
- writes.push(pkg.write());
178
- }
179
- await Promise.all(writes);
180
- },
181
- cli: { async draftApplied() {
182
- if (!active || !updateLockFile) return;
183
- let args;
184
- if (client === "npm") args = ["ci"];
185
- else if (client === "yarn") args = ["install", "--immutable"];
186
- else if (client === "bun") args = ["install", "--frozen-lockfile"];
187
- else args = ["install", "--frozen-lockfile"];
188
- const result = await x(client, args, { nodeOptions: { cwd: this.cwd } });
189
- if (result.exitCode !== 0) throw execFailure("Failed to update lockfile.", result);
190
- } }
191
- };
192
- }
193
- function depsPolicy(context, getBumpDepType) {
194
- const { graph } = context;
195
- function needsUpdate(spec, target) {
196
- if (spec.linked && spec.protocol === "workspace") switch (spec.range) {
197
- case "":
198
- case "*": return true;
199
- case "^":
200
- case "~": return !semver.satisfies(target, `${spec.range}${spec.linked.version}`);
201
- }
202
- if (spec.linked && spec.protocol === "file") return true;
203
- if (spec.protocol === "file" || !semver.validRange(spec.range)) return false;
204
- return !semver.satisfies(target, spec.range);
205
- }
206
- return {
207
- id: "npm:deps",
208
- onUpdate({ pkg, packageDraft: plan }) {
209
- if (!(pkg instanceof NpmPackage)) return;
210
- const group = graph.getPackageGroup(pkg.id);
211
- for (const dependent of graph.getPackages()) {
212
- if (!(dependent instanceof NpmPackage)) continue;
213
- for (const field of DEP_FIELDS) {
214
- const dependencies = dependent.manifest[field];
215
- if (!dependencies) continue;
216
- for (const [k, v] of Object.entries(dependencies)) {
217
- const spec = parseDependencySpec(context, dependent, k, v);
218
- if (!spec || spec.linked !== pkg) continue;
219
- if (group?.options.syncBump && graph.getPackageGroup(dependent.id) === group) continue;
220
- if (!needsUpdate(spec, plan.bumpVersion(pkg))) continue;
221
- const bumpType = getBumpDepType({
222
- kind: field,
223
- spec,
224
- name: k
225
- });
226
- if (bumpType === false) continue;
227
- this.bumpPackage(dependent, {
228
- type: bumpType,
229
- reason: `update dependency "${k}"`
230
- });
231
- }
232
- }
233
- }
234
- }
235
- };
236
- }
237
- async function publish(client, pkg, distTag) {
238
- if (client === "bun") {
239
- for (const script of [
240
- "prepublishOnly",
241
- "prepack",
242
- "prepare"
243
- ]) {
244
- if (!pkg.manifest.scripts?.[script]) continue;
245
- const result = await x("bun", ["run", script], { nodeOptions: { cwd: pkg.path } });
246
- if (result.exitCode === 0) continue;
247
- return {
248
- type: "failed",
249
- error: execFailure(`Failed to run ${script} script for ${pkg.name}@${pkg.version}.`, result).message
250
- };
251
- }
252
- const tarballPath = path.resolve(pkg.path, "pkg.tgz");
253
- const packResult = await x("bun", [
254
- "pm",
255
- "pack",
256
- "--filename",
257
- tarballPath
258
- ], { nodeOptions: { cwd: pkg.path } });
259
- if (packResult.exitCode !== 0) return {
260
- type: "failed",
261
- error: execFailure(`Failed to pack ${pkg.name}@${pkg.version}.`, packResult).message
262
- };
263
- const publishArgs = ["publish", tarballPath];
264
- if (distTag) publishArgs.push("--tag", distTag);
265
- const publishResult = await x("npm", publishArgs, { nodeOptions: { cwd: pkg.path } });
266
- if (publishResult.exitCode !== 0) return {
267
- type: "failed",
268
- error: execFailure(`Failed to publish ${pkg.name}@${pkg.version}${distTag ? ` with dist-tag "${distTag}"` : ""}.`, publishResult).message
269
- };
270
- return { type: "published" };
271
- }
272
- let command;
273
- const args = ["publish"];
274
- if (distTag) args.push("--tag", distTag);
275
- if (client === "pnpm") {
276
- command = "pnpm";
277
- args.push("--no-git-checks");
278
- } else if (client === "yarn") command = "yarn";
279
- else command = "npm";
280
- const result = await x(command, args, { nodeOptions: { cwd: pkg.path } });
281
- if (result.exitCode !== 0) return {
282
- type: "failed",
283
- error: execFailure(`Failed to publish ${pkg.name}@${pkg.version}${distTag ? ` with dist-tag "${distTag}"` : ""}.`, result).message
284
- };
285
- return { type: "published" };
286
- }
287
- async function isPackagePublished(pkg) {
288
- const registry = pkg.manifest.publishConfig?.registry ?? "https://registry.npmjs.org";
289
- const base = registry.replace(/\/$/, "");
290
- const response = await fetch(`${base}/${pkg.name}/${pkg.version}`, { headers: { Accept: "application/json" } });
291
- if (response.status === 404) return false;
292
- if (!response.ok) throw new Error(`Unable to validate ${pkg.name}@${pkg.version} against the npm registry${registry ? ` "${registry}"` : ""}.`);
293
- return true;
294
- }
295
- async function discoverNpmPackages(cwd, add) {
296
- let patterns;
297
- const rootManifest = await readManifest(cwd).catch(() => void 0);
298
- const pnpmPatterns = await readFile(path.join(cwd, "pnpm-workspace.yaml"), "utf8").then((content) => pnpmWorkspaceSchema.parse(load(content) ?? {})).catch((error) => {
299
- if (isNodeError(error) && error.code === "ENOENT") return void 0;
300
- throw error;
301
- });
302
- if (pnpmPatterns) patterns = pnpmPatterns.packages ?? [];
303
- else patterns = rootManifest?.workspaces ?? [];
304
- const candidatePaths = await expandWorkspacePatterns(cwd, patterns);
305
- const manifests = await Promise.all(candidatePaths.map((path) => readManifest(path).then((manifest) => ({
306
- path,
307
- manifest
308
- })).catch(() => void 0)));
309
- if (rootManifest?.version) add(new NpmPackage(cwd, rootManifest));
310
- for (const entry of manifests) {
311
- if (!entry?.manifest.version) continue;
312
- add(new NpmPackage(entry.path, entry.manifest));
313
- }
314
- }
315
- async function expandWorkspacePatterns(cwd, patterns) {
316
- if (patterns.length === 0) return [];
317
- return (await glob(patterns, {
318
- absolute: true,
319
- cwd,
320
- ignore: ["**/node_modules/**", "**/dist/**"],
321
- onlyDirectories: true,
322
- onlyFiles: false
323
- })).map((item) => {
324
- return item.endsWith(path.sep) ? item.slice(0, -1) : item;
325
- });
326
- }
327
- async function readManifest(packagePath) {
328
- const content = await readFile(path.join(packagePath, "package.json"), "utf8");
329
- const parsed = JSON.parse(content);
330
- packageManifestSchema.parse(parsed);
331
- return parsed;
332
- }
333
- //#endregion
1
+ import { n as npm, t as NpmPackage } from "../npm-DqGyAsdo.js";
334
2
  export { NpmPackage, npm };
@@ -4,7 +4,10 @@ function formatNpmDistTag(distTag) {
4
4
  return distTag && distTag !== "latest" ? ` (${distTag})` : "";
5
5
  }
6
6
  function formatPackageVersion(name, version, distTag) {
7
- return `${name}@${version}${formatNpmDistTag(distTag)}`;
7
+ let out = name;
8
+ if (version) out += `@${version}`;
9
+ out += formatNpmDistTag(distTag);
10
+ return out;
8
11
  }
9
12
  const WEIGHTS = {
10
13
  major: 3,
@@ -33,7 +36,8 @@ function bumpVersion(version, type, prerelease) {
33
36
  const parsed = parse(version);
34
37
  if (!parsed) next = null;
35
38
  else if (prerelease) {
36
- if (parsed.prerelease[0] === prerelease && type) next = inc(parsed, "prerelease", prerelease);
39
+ if (parsed.prerelease[0] === prerelease) next = type ? inc(parsed, "prerelease", prerelease) : version;
40
+ else if (parsed.prerelease[0]) next = inc(parsed, "prerelease", prerelease);
37
41
  else if (type) next = inc(parsed, PRE[type], prerelease);
38
42
  } else if (type) next = inc(parsed, type);
39
43
  else if (parsed.prerelease.length > 0) next = inc(parsed, "release");
@@ -1,4 +1,4 @@
1
- import z, { z as z$1 } from "zod";
1
+ import z from "zod";
2
2
  import { AgentName } from "package-manager-detector";
3
3
 
4
4
  //#region src/utils/semver.d.ts
@@ -42,8 +42,8 @@ interface PackageDraft {
42
42
  npm?: {
43
43
  /** npm dist-tag used when publishing. */distTag?: string;
44
44
  };
45
- /** get the bumped version of a package */
46
- bumpVersion: (pkg: WorkspacePackage) => string;
45
+ /** get the bumped version of a package, return `undefined` if the package doesn't have a `version` field */
46
+ bumpVersion: (pkg: WorkspacePackage) => string | undefined;
47
47
  }
48
48
  /** a draft describes all operations to perform before the actual publishing, such as version bumps. */
49
49
  declare class Draft {
@@ -67,6 +67,7 @@ declare class Draft {
67
67
  dispatchPackage(pkg: WorkspacePackage, dispatch: (draft: PackageDraft) => void, onUpdate?: (draft: PackageDraft) => void): PackageDraft;
68
68
  getOrInitPackage(pkg: WorkspacePackage): PackageDraft;
69
69
  hasPending(): boolean;
70
+ /** get all changelogs, note that this includes replay-only changelogs, as long as they are in the `.tegami` folder. */
70
71
  getChangelogs(): ChangelogEntry[];
71
72
  getChangelog(id: string): ChangelogEntry | undefined;
72
73
  addChangelog(entry: ChangelogEntry): void;
@@ -96,9 +97,10 @@ interface DraftPolicy {
96
97
  /** Package discovered in the workspace. */
97
98
  declare abstract class WorkspacePackage {
98
99
  abstract readonly name: string;
100
+ /** absolute path */
99
101
  abstract readonly path: string;
100
102
  abstract readonly manager: string;
101
- abstract readonly version: string;
103
+ abstract readonly version: string | undefined;
102
104
  get id(): string;
103
105
  private opts;
104
106
  /** note: this will only be available after package graph is resolved */
@@ -158,141 +160,27 @@ interface TegamiContext {
158
160
  };
159
161
  }
160
162
  //#endregion
161
- //#region src/changelog/generate.d.ts
162
- interface GenerateFromCommitsOptions {
163
- /** Start revision. Defaults to the latest reachable git tag, or all history if none exists. */
164
- from?: string;
165
- /** End revision. Defaults to HEAD. */
166
- to?: string;
167
- }
168
- interface CommitChangelog {
169
- filename: string;
170
- content: string;
171
- packages: Record<string, BumpType | ChangelogPackageConfig>;
172
- changes: CommitChange[];
173
- }
174
- interface CommitChange {
175
- hash: string;
176
- subject: string;
177
- body: string;
178
- packages: string[];
179
- type: BumpType;
180
- title: string;
181
- }
182
- //#endregion
183
- //#region src/plans/publish.d.ts
184
- interface PublishPlan {
185
- options: PublishOptions;
186
- /** id -> entry */
187
- changelogs: Map<string, ChangelogEntry>;
188
- /** id -> package data. The package id will always exist in package graph, stale items will be pruned at init-time */
189
- packages: Map<string, PackagePublishPlan>;
190
- }
191
- interface PackagePublishPlan {
192
- changelogs: ChangelogEntry[];
193
- /** whether this package was version-bumped when the lock was written */
194
- updated: boolean;
195
- /** generated by Git plugin */
196
- git?: {
197
- /** the associated Git tag of package */tag: string;
198
- };
199
- /** generated by npm plugin */
200
- npm?: {
201
- /** dist tag to use if published */distTag?: string;
202
- };
203
- /** publish result, generated for all packages in publish plan after publishing */
204
- publishResult?: PackagePublishResult;
205
- /** preflight result, generated for all packages in publish plan after preflights */
206
- preflight?: PublishPreflight;
207
- }
208
- interface PublishOptions {
209
- /** Validate the publish plan without publishing packages, creating tags, or running release plugins. */
210
- dryRun?: boolean;
211
- }
212
- type PackagePublishResult = {
213
- type: "published" | "skipped";
214
- } | {
215
- type: "failed";
216
- error: string;
217
- };
218
- //#endregion
219
- //#region src/plans/lock.d.ts
220
- /**
221
- * the data structure of `publish-lock.yaml` file.
222
- */
223
- declare class PublishLock {
224
- /** namespace -> data array */
225
- private readonly data;
226
- constructor(/** namespace -> data array */
227
-
228
- data?: Map<string, unknown[]>);
229
- /** write data to namespace, note that the `data` must be serializable in yaml */
230
- write(namespace: string, data: unknown): void;
231
- read(namespace: string): unknown | undefined;
232
- size(namespace: string): number;
233
- serialize(): string;
234
- }
235
- //#endregion
236
- //#region src/index.d.ts
237
- interface GenerateChangelogOptions extends GenerateFromCommitsOptions {
238
- /**
239
- * Write changelog files to disk.
240
- *
241
- * @default true
242
- */
243
- write?: boolean;
244
- }
245
- interface Tegami {
246
- /** Create pending changelog files from git commit history. */
247
- generateChangelog(options?: GenerateChangelogOptions): Promise<CommitChangelog[]>;
248
- /** Build a draft from pending changelog files. */
249
- draft(): Promise<Draft>;
250
- /** Publish packages from the publish lock. */
251
- publish(options?: PublishOptions): Promise<PublishPlan | "skipped">;
252
- /**
253
- * Check publish status.
254
- *
255
- * Prefer `publish()` over this if you are publishing packages, it will also check the publish status.
256
- */
257
- publishStatus(): Promise<"pending" | "success" | "idle">;
258
- /** Remove the publish lock file after publishing has finished successfully. */
259
- cleanup(): Promise<{
260
- state: "removed";
261
- } | {
262
- state: "skipped";
263
- reason: "no-plan" | "pending";
264
- }>;
265
- /** Internal APIs, do not use it unless you know what you are doing */
266
- _internal: {
267
- context(): Promise<TegamiContext>;
268
- graph(): Promise<PackageGraph>;
269
- options: TegamiOptions;
270
- };
271
- }
272
- /** Create a Tegami project handle. */
273
- declare function tegami<const Groups extends string = string>(options?: TegamiOptions<Groups>): Tegami;
274
- //#endregion
275
- //#region src/schemas.d.ts
276
- declare const packageManifestSchema: z$1.ZodObject<{
277
- name: z$1.ZodString;
278
- version: z$1.ZodOptional<z$1.ZodString>;
279
- private: z$1.ZodOptional<z$1.ZodBoolean>;
280
- publishConfig: z$1.ZodOptional<z$1.ZodObject<{
281
- access: z$1.ZodOptional<z$1.ZodEnum<{
163
+ //#region src/providers/npm/schema.d.ts
164
+ declare const packageManifestSchema: z.ZodObject<{
165
+ name: z.ZodString;
166
+ version: z.ZodOptional<z.ZodString>;
167
+ private: z.ZodOptional<z.ZodBoolean>;
168
+ publishConfig: z.ZodOptional<z.ZodObject<{
169
+ access: z.ZodOptional<z.ZodEnum<{
282
170
  public: "public";
283
171
  restricted: "restricted";
284
172
  }>>;
285
- registry: z$1.ZodOptional<z$1.ZodString>;
286
- tag: z$1.ZodOptional<z$1.ZodString>;
287
- }, z$1.core.$loose>>;
288
- scripts: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodString>>;
289
- workspaces: z$1.ZodOptional<z$1.ZodArray<z$1.ZodString>>;
290
- dependencies: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodString>>;
291
- devDependencies: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodString>>;
292
- peerDependencies: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodString>>;
293
- optionalDependencies: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodString>>;
294
- }, z$1.core.$loose>;
295
- type PackageManifest = z$1.infer<typeof packageManifestSchema>;
173
+ registry: z.ZodOptional<z.ZodString>;
174
+ tag: z.ZodOptional<z.ZodString>;
175
+ }, z.core.$loose>>;
176
+ scripts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
177
+ workspaces: z.ZodOptional<z.ZodArray<z.ZodString>>;
178
+ dependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
179
+ devDependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
180
+ peerDependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
181
+ optionalDependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
182
+ }, z.core.$loose>;
183
+ type PackageManifest = z.infer<typeof packageManifestSchema>;
296
184
  //#endregion
297
185
  //#region src/providers/npm.d.ts
298
186
  declare const DEP_FIELDS$1: readonly ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
@@ -302,9 +190,10 @@ declare class NpmPackage extends WorkspacePackage {
302
190
  readonly manager = "npm";
303
191
  constructor(path: string, manifest: PackageManifest);
304
192
  get name(): string;
305
- get version(): string;
193
+ get version(): string | undefined;
306
194
  write(): Promise<void>;
307
195
  initDraft(): PackageDraft;
196
+ configureDraft(draft: PackageDraft, group?: PackageGroup): void;
308
197
  }
309
198
  type DependencySpec = {
310
199
  protocol: "npm";
@@ -331,6 +220,7 @@ interface NpmPluginOptions {
331
220
  * Decide how to bump the dependents of a bumped package.
332
221
  */
333
222
  bumpDep?: (opts: {
223
+ dependent: NpmPackage;
334
224
  kind: (typeof DEP_FIELDS$1)[number];
335
225
  name: string;
336
226
  spec: DependencySpec;
@@ -369,7 +259,7 @@ declare class CargoPackage extends WorkspacePackage {
369
259
  readonly manager = "cargo";
370
260
  constructor(path: string, manifest: TomlTable, content: string, workspaceManifest?: TomlTable | undefined);
371
261
  get name(): string;
372
- get version(): string;
262
+ get version(): string | undefined;
373
263
  setVersion(version: string): void;
374
264
  write(): Promise<void>;
375
265
  patch(path: string, value: unknown): void;
@@ -383,7 +273,11 @@ interface CargoPluginOptions {
383
273
  * @default true
384
274
  */
385
275
  updateLockFile?: boolean;
276
+ /**
277
+ * Decide how to bump the dependents of a bumped package.
278
+ */
386
279
  bumpDep?: (opts: {
280
+ dependent: CargoPackage;
387
281
  kind: (typeof DEP_FIELDS)[number];
388
282
  name: string;
389
283
  version: string;
@@ -394,6 +288,59 @@ declare function cargo({
394
288
  bumpDep: getBumpDepType
395
289
  }?: CargoPluginOptions): TegamiPlugin;
396
290
  //#endregion
291
+ //#region src/plans/publish.d.ts
292
+ interface PublishPlan {
293
+ options: PublishOptions;
294
+ /** id -> entry */
295
+ changelogs: Map<string, ChangelogEntry>;
296
+ /** id -> package data. The package id will always exist in package graph, stale items will be pruned at init-time */
297
+ packages: Map<string, PackagePublishPlan>;
298
+ }
299
+ interface PackagePublishPlan {
300
+ changelogs: ChangelogEntry[];
301
+ /** whether this package was version-bumped when the lock was written */
302
+ updated: boolean;
303
+ /** generated by Git plugin */
304
+ git?: {
305
+ /** the associated Git tag of package */tag?: string;
306
+ };
307
+ /** generated by npm plugin */
308
+ npm?: {
309
+ /** dist tag to use if published */distTag?: string;
310
+ };
311
+ /** publish result, generated for all packages in publish plan after publishing */
312
+ publishResult?: PackagePublishResult;
313
+ /** preflight result, generated for all packages in publish plan after preflights */
314
+ preflight?: PublishPreflight;
315
+ }
316
+ interface PublishOptions {
317
+ /** Validate the publish plan without publishing packages, creating tags, or running release plugins. */
318
+ dryRun?: boolean;
319
+ }
320
+ type PackagePublishResult = {
321
+ type: "published" | "skipped";
322
+ } | {
323
+ type: "failed";
324
+ error: string;
325
+ };
326
+ //#endregion
327
+ //#region src/plans/lock.d.ts
328
+ /**
329
+ * the data structure of `publish-lock.yaml` file.
330
+ */
331
+ declare class PublishLock {
332
+ /** namespace -> data array */
333
+ private readonly data;
334
+ constructor(/** namespace -> data array */
335
+
336
+ data?: Map<string, unknown[]>);
337
+ /** write data to namespace, note that the `data` must be serializable in yaml */
338
+ write(namespace: string, data: unknown): void;
339
+ read(namespace: string): unknown | undefined;
340
+ size(namespace: string): number;
341
+ serialize(): string;
342
+ }
343
+ //#endregion
397
344
  //#region src/types.d.ts
398
345
  /** Generates changelog content for a package release. */
399
346
  interface LogGenerator {
@@ -412,8 +359,8 @@ interface TegamiOptions<Groups extends string = string> {
412
359
  lockPath?: string;
413
360
  /** Changelog generator used when applying a draft. */
414
361
  generator?: LogGenerator;
415
- /** Per-package release and publish options keyed by package name. */
416
- packages?: Record<string, PackageOptions<NoInfer<Groups>>>;
362
+ /** Per-package options keyed by package name or a function. */
363
+ packages?: Record<string, PackageOptions<NoInfer<Groups>>> | ((pkg: WorkspacePackage) => PackageOptions<NoInfer<Groups>> | undefined);
417
364
  plugins?: TegamiPluginOption[];
418
365
  groups?: Record<Groups, GroupOptions>;
419
366
  /** Package names, ids, or regex patterns to exclude from the dependency graph. */
@@ -455,7 +402,7 @@ type TegamiPluginOption = TegamiPlugin | TegamiPluginOption[];
455
402
  interface TegamiPlugin {
456
403
  name: string;
457
404
  enforce?: "pre" | "default" | "post";
458
- /** when Tegami initializes */
405
+ /** When Tegami initializes */
459
406
  init?(this: TegamiContext): Awaitable<void>;
460
407
  /** Resolve workspace packages and dependency metadata into the shared graph. */
461
408
  resolve?(this: TegamiContext): Awaitable<void>;
@@ -495,7 +442,7 @@ interface TegamiPlugin {
495
442
  willPublish?(this: TegamiContext, opts: {
496
443
  pkg: WorkspacePackage;
497
444
  }): Awaitable<false | void | undefined>;
498
- /** Called after a package is published, skipped, or failed. */
445
+ /** Called after a package is published successfully, or failed. */
499
446
  afterPublish?(this: TegamiContext, opts: {
500
447
  pkg: WorkspacePackage;
501
448
  plan: PublishPlan;
@@ -523,4 +470,4 @@ interface PublishPreflight {
523
470
  wait?: string[];
524
471
  }
525
472
  //#endregion
526
- export { PackageDraft as A, CommitChangelog as C, WorkspacePackage as D, PackageGroup as E, Draft as O, PublishPlan as S, PackageGraph as T, tegami as _, PublishPreflight as a, PackagePublishResult as b, TegamiPluginOption as c, cargo as d, NpmPackage as f, Tegami as g, GenerateChangelogOptions as h, PackageOptions as i, DraftPolicy as k, CargoPackage as l, npm as m, GroupOptions as n, TegamiOptions as o, NpmPluginOptions as p, LogGenerator as r, TegamiPlugin as s, Awaitable as t, CargoPluginOptions as u, PublishLock as v, TegamiContext as w, PublishOptions as x, PackagePublishPlan as y };
473
+ export { WorkspacePackage as C, ChangelogPackageConfig as D, PackageDraft as E, BumpType as O, PackageGroup as S, DraftPolicy as T, NpmPackage as _, PublishPreflight as a, TegamiContext as b, TegamiPluginOption as c, PackagePublishResult as d, PublishOptions as f, cargo as g, CargoPluginOptions as h, PackageOptions as i, PublishLock as l, CargoPackage as m, GroupOptions as n, TegamiOptions as o, PublishPlan as p, LogGenerator as r, TegamiPlugin as s, Awaitable as t, PackagePublishPlan as u, NpmPluginOptions as v, Draft as w, PackageGraph as x, npm as y };