tegami 0.0.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.
@@ -0,0 +1,283 @@
1
+ import * as semver from "semver";
2
+ import { SemVer } from "semver";
3
+ import { z } from "zod";
4
+
5
+ //#region src/workspace.d.ts
6
+ /** Package discovered in the workspace. */
7
+ declare abstract class WorkspacePackage {
8
+ abstract readonly name: string;
9
+ abstract readonly path: string;
10
+ abstract readonly manager: string;
11
+ abstract readonly version: string;
12
+ abstract readonly publish: boolean;
13
+ get distTag(): string | undefined;
14
+ get id(): string;
15
+ setVersion?(version: string): void;
16
+ updateDependency?(target: WorkspacePackage, version: string, context: TegamiContext): Awaitable<void>;
17
+ write?(): Awaitable<void>;
18
+ protected updateRange(context: TegamiContext, spec: DependencySpec, next: semver.SemVer): Promise<DependencySpec>;
19
+ }
20
+ /** Dependency graph for discovered workspace packages. */
21
+ declare class PackageGraph {
22
+ private readonly byId;
23
+ private readonly byName;
24
+ constructor(packages?: WorkspacePackage[]);
25
+ getPackages(): WorkspacePackage[];
26
+ /** Get a package by exact id. */
27
+ get(id: string): WorkspacePackage | undefined;
28
+ /** Get packages by id, or every package matching a name. */
29
+ getByName(nameOrId: string): WorkspacePackage[];
30
+ /** scan package into graph, if the package id already exists, replace the existing one in graph */
31
+ add(pkg: WorkspacePackage): void;
32
+ delete(pkg: WorkspacePackage): void;
33
+ }
34
+ //#endregion
35
+ //#region src/context.d.ts
36
+ interface TegamiContext {
37
+ cwd: string;
38
+ changelogDir: string;
39
+ planPath: string;
40
+ options: TegamiOptions;
41
+ plugins: TegamiPlugin[];
42
+ graph: PackageGraph;
43
+ /** error if doesn't exist */
44
+ getRegistryClient(pkgOrId: WorkspacePackage | string): RegistryClient;
45
+ }
46
+ //#endregion
47
+ //#region src/utils/semver.d.ts
48
+ type BumpType = "major" | "minor" | "patch";
49
+ //#endregion
50
+ //#region src/changelog/parse.d.ts
51
+ interface ChangelogEntry {
52
+ id: string;
53
+ /** file name like `my-change.md` */
54
+ filename: string;
55
+ subject?: string;
56
+ packages: Set<string>;
57
+ type: BumpType;
58
+ title: string;
59
+ content: string;
60
+ }
61
+ //#endregion
62
+ //#region src/draft.d.ts
63
+ /** Per-package options applied when creating publish plans. */
64
+ interface PackageOptions {
65
+ /** npm dist-tag used when publishing. */
66
+ distTag?: string;
67
+ /** Set to false to keep this package out of npm publishing. */
68
+ publish?: boolean;
69
+ }
70
+ interface PackagePlan {
71
+ type: BumpType;
72
+ changelogIds: Set<string>;
73
+ distTag?: string;
74
+ publish: boolean;
75
+ }
76
+ declare class DraftPlan {
77
+ #private;
78
+ private readonly changelogs;
79
+ private readonly packages;
80
+ private readonly context;
81
+ constructor(changelogs: Map<string, ChangelogEntry>, packages: Map<string, PackagePlan>, context: TegamiContext);
82
+ getPackageIds(): string[];
83
+ getPackage(id: string): PackagePlan | undefined;
84
+ setPackage(id: string, plan?: Partial<PackagePlan>): void;
85
+ deletePackage(id: string): boolean;
86
+ getChangelogIds(): string[];
87
+ getChangelog(id: string): ChangelogEntry | undefined;
88
+ setChangelog(id: string, entry: ChangelogEntry): void;
89
+ deleteChangelog(id: string): boolean;
90
+ /** Write the publish plan, update package versions, and consume changelog files. */
91
+ createPublishPlan(): Promise<void>;
92
+ private assertPublishPlanFinished;
93
+ private applyVersionChanges;
94
+ private removeConsumedChangelogs;
95
+ private assertEditable;
96
+ private appendChangelog;
97
+ /** {@link createPublishPlan} but for `await using` syntax */
98
+ [Symbol.asyncDispose](): Promise<void>;
99
+ }
100
+ //#endregion
101
+ //#region src/schemas.d.ts
102
+ declare const packageManifestSchema: z.ZodObject<{
103
+ name: z.ZodOptional<z.ZodString>;
104
+ version: z.ZodOptional<z.ZodString>;
105
+ private: z.ZodOptional<z.ZodBoolean>;
106
+ publishConfig: z.ZodOptional<z.ZodObject<{
107
+ access: z.ZodOptional<z.ZodEnum<{
108
+ public: "public";
109
+ restricted: "restricted";
110
+ }>>;
111
+ registry: z.ZodOptional<z.ZodString>;
112
+ tag: z.ZodOptional<z.ZodString>;
113
+ }, z.core.$loose>>;
114
+ workspaces: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodArray<z.ZodString>, z.ZodPipe<z.ZodObject<{
115
+ packages: z.ZodOptional<z.ZodArray<z.ZodString>>;
116
+ }, z.core.$loose>, z.ZodTransform<string[], {
117
+ [x: string]: unknown;
118
+ packages?: string[] | undefined;
119
+ }>>]>, z.ZodArray<z.ZodString>>>;
120
+ dependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
121
+ devDependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
122
+ peerDependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
123
+ optionalDependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
124
+ }, z.core.$loose>;
125
+ type PackageManifest = z.infer<typeof packageManifestSchema>;
126
+ /** the persisted plan data for actual publishing */
127
+ declare const planStoreSchema: z.ZodCodec<z.ZodString, z.ZodObject<{
128
+ id: z.ZodString;
129
+ createdAt: z.ZodISODateTime;
130
+ changelogs: z.ZodRecord<z.ZodString, z.ZodObject<{
131
+ filename: z.ZodString;
132
+ subject: z.ZodOptional<z.ZodString>;
133
+ packages: z.ZodArray<z.ZodString>;
134
+ type: z.ZodEnum<{
135
+ major: "major";
136
+ minor: "minor";
137
+ patch: "patch";
138
+ }>;
139
+ title: z.ZodString;
140
+ content: z.ZodString;
141
+ }, z.core.$strip>>;
142
+ packages: z.ZodRecord<z.ZodString, z.ZodObject<{
143
+ type: z.ZodEnum<{
144
+ major: "major";
145
+ minor: "minor";
146
+ patch: "patch";
147
+ }>;
148
+ changelogIds: z.ZodCodec<z.ZodArray<z.ZodString>, z.ZodSet<z.ZodString>>;
149
+ distTag: z.ZodOptional<z.ZodString>;
150
+ publish: z.ZodBoolean;
151
+ }, z.core.$strip>>;
152
+ }, z.core.$strip>>;
153
+ type PlanStore = z.output<typeof planStoreSchema>;
154
+ //#endregion
155
+ //#region src/publish.d.ts
156
+ interface PublishOptions {
157
+ /** Validate the publish plan without publishing packages, creating tags, or running release plugins. */
158
+ dryRun?: boolean;
159
+ }
160
+ interface PublishResult {
161
+ /** Path to the publish plan that was executed. */
162
+ planPath: string;
163
+ state: "success" | "failed";
164
+ packages: PackagePublishResult[];
165
+ /** the persisted plan object. This is not a public API, can be changed without notice */
166
+ _rawPlan: PlanStore;
167
+ }
168
+ type PackagePublishResult = ({
169
+ state: "failed";
170
+ error?: string;
171
+ } | {
172
+ state: "success";
173
+ }) & {
174
+ id: string;
175
+ name: string;
176
+ version: string;
177
+ distTag: string | undefined; /** added by the `git` plugin */
178
+ gitTag?: string;
179
+ changelogs: ChangelogEntry[];
180
+ };
181
+ //#endregion
182
+ //#region src/providers/npm.d.ts
183
+ declare class NpmPackage extends WorkspacePackage {
184
+ readonly path: string;
185
+ readonly manifest: PackageManifest;
186
+ readonly manager = "npm";
187
+ constructor(path: string, manifest: PackageManifest);
188
+ get name(): string;
189
+ get version(): string;
190
+ get publish(): boolean;
191
+ get distTag(): string | undefined;
192
+ setVersion(version: string): void;
193
+ updateDependency(target: WorkspacePackage, version: string, context: TegamiContext): Promise<void>;
194
+ write(): Promise<void>;
195
+ }
196
+ type NpmClient = "npm" | "pnpm";
197
+ declare class NpmRegistryClient implements RegistryClient {
198
+ #private;
199
+ private readonly cwd;
200
+ private readonly npmClient;
201
+ private readonly graph;
202
+ readonly id = "npm";
203
+ constructor(cwd: string, npmClient: NpmClient | undefined, graph: {
204
+ get(id: string): WorkspacePackage | undefined;
205
+ });
206
+ supports(pkg: WorkspacePackage): boolean;
207
+ packageVersionExists(pkg: WorkspacePackage, version: string): Promise<boolean>;
208
+ publish(pkg: WorkspacePackage, options?: {
209
+ distTag?: string;
210
+ }): Promise<void>;
211
+ publishPlanStatus(plan: PlanStore): Promise<PublishPlanStatus>;
212
+ private resolveClient;
213
+ }
214
+ declare function npm(client?: NpmClient): TegamiPlugin;
215
+ //#endregion
216
+ //#region src/types.d.ts
217
+ /** Generates changelog content for a package release. */
218
+ interface LogGenerator {
219
+ generate(this: TegamiContext, opts: {
220
+ packageName: string;
221
+ version: string;
222
+ changelogs: ChangelogEntry[];
223
+ }): string | Promise<string>;
224
+ }
225
+ interface TegamiOptions {
226
+ /** Workspace root. Defaults to the current working directory. */
227
+ cwd?: string;
228
+ /** Directory containing pending changelog markdown files. */
229
+ changelogDir?: string;
230
+ /** Path to the publish plan file. */
231
+ planPath?: string;
232
+ /** Changelog generator used when creating a publish plan. */
233
+ generator?: LogGenerator;
234
+ /** Per-package release and publish options keyed by package name. */
235
+ packages?: Record<string, PackageOptions>;
236
+ plugins?: TegamiPluginOption[];
237
+ /** Package manager command used for npm registry operations. */
238
+ npmClient?: NpmClient;
239
+ }
240
+ type TegamiPluginOption = TegamiPlugin | TegamiPluginOption[];
241
+ interface TegamiPlugin {
242
+ name: string;
243
+ enforce?: "pre" | "default" | "post";
244
+ /** when Tegami initializes */
245
+ init?(this: TegamiContext): Awaitable<void>;
246
+ /** Resolve workspace packages and dependency metadata into the shared graph. */
247
+ resolve?(this: TegamiContext): Awaitable<void>;
248
+ /** Register registry clients used to handle packages for different package managers. */
249
+ createRegistryClient?(this: TegamiContext): Awaitable<RegistryClient | RegistryClient[] | void | undefined>;
250
+ /** Called after Tegami builds the initial draft plan and before it is returned. */
251
+ initPlan?(this: TegamiContext, plan: DraftPlan): Awaitable<DraftPlan | void | undefined>;
252
+ /** Called after publishing finishes. */
253
+ afterPublish?(this: TegamiContext & {
254
+ publishOptions: PublishOptions;
255
+ }, result: PublishResult): Awaitable<PublishResult | void | undefined>;
256
+ /**
257
+ * @param pkg - the package that referenced the dependency
258
+ * @param spec - the referenced dependency & its range
259
+ * @param target - the target version to update to
260
+ * @returns fallback to the default behaviour if `undefined`, otherwise replace with updated spec (can reuse the same instance, as long as a value is returned).
261
+ */
262
+ onUpdateRange?(this: TegamiContext, pkg: WorkspacePackage, spec: DependencySpec, target: SemVer): Awaitable<DependencySpec | void | undefined>;
263
+ }
264
+ type Awaitable<T> = T | Promise<T>;
265
+ interface PublishPlanStatus {
266
+ state: "pending" | "success";
267
+ error?: string;
268
+ }
269
+ interface RegistryClient {
270
+ id: string;
271
+ supports?(pkg: WorkspacePackage): boolean;
272
+ packageVersionExists(pkg: WorkspacePackage, version: string): Promise<boolean>;
273
+ publish(pkg: WorkspacePackage, options?: {
274
+ distTag?: string;
275
+ }): Promise<void>;
276
+ publishPlanStatus(plan: PlanStore): Promise<PublishPlanStatus>;
277
+ }
278
+ interface DependencySpec {
279
+ name: string;
280
+ range: string;
281
+ }
282
+ //#endregion
283
+ export { PackageOptions as _, TegamiOptions as a, PackageGraph as b, NpmClient as c, npm as d, PackagePublishResult as f, DraftPlan as g, PlanStore as h, RegistryClient as i, NpmPackage as l, PublishResult as m, LogGenerator as n, TegamiPlugin as o, PublishOptions as p, PublishPlanStatus as r, TegamiPluginOption as s, Awaitable as t, NpmRegistryClient as u, PackagePlan as v, WorkspacePackage as x, TegamiContext as y };
@@ -0,0 +1,63 @@
1
+ import * as semver from "semver";
2
+ //#region src/utils/error.ts
3
+ function isNodeError(error) {
4
+ return error instanceof Error && "code" in error;
5
+ }
6
+ //#endregion
7
+ //#region src/workspace.ts
8
+ /** Package discovered in the workspace. */
9
+ var WorkspacePackage = class {
10
+ get distTag() {}
11
+ get id() {
12
+ return `${this.manager}:${this.name}`;
13
+ }
14
+ async updateRange(context, spec, next) {
15
+ for (const plugin of context.plugins) {
16
+ const result = await plugin.onUpdateRange?.call(context, this, spec, next);
17
+ if (result) return result;
18
+ }
19
+ if (!semver.validRange(spec.range)) return spec;
20
+ if (new semver.Range(spec.range).test(next)) return spec;
21
+ spec.range = next.format();
22
+ return spec;
23
+ }
24
+ };
25
+ /** Dependency graph for discovered workspace packages. */
26
+ var PackageGraph = class {
27
+ byId = /* @__PURE__ */ new Map();
28
+ byName = /* @__PURE__ */ new Map();
29
+ constructor(packages = []) {
30
+ for (const pkg of packages) this.add(pkg);
31
+ }
32
+ getPackages() {
33
+ return Array.from(this.byId.values());
34
+ }
35
+ /** Get a package by exact id. */
36
+ get(id) {
37
+ return this.byId.get(id);
38
+ }
39
+ /** Get packages by id, or every package matching a name. */
40
+ getByName(nameOrId) {
41
+ const exact = this.byId.get(nameOrId);
42
+ if (exact) return [exact];
43
+ return this.byName.get(nameOrId) ?? [];
44
+ }
45
+ /** scan package into graph, if the package id already exists, replace the existing one in graph */
46
+ add(pkg) {
47
+ const existing = this.byId.get(pkg.id);
48
+ if (existing) this.delete(existing);
49
+ this.byId.set(pkg.id, pkg);
50
+ const named = this.byName.get(pkg.name);
51
+ if (named) named.push(pkg);
52
+ else this.byName.set(pkg.name, [pkg]);
53
+ }
54
+ delete(pkg) {
55
+ this.byId.delete(pkg.id);
56
+ const named = this.byName.get(pkg.name);
57
+ if (!named) return;
58
+ const index = named.findIndex((item) => item.id === pkg.id);
59
+ if (index !== -1) named.splice(index, 1);
60
+ }
61
+ };
62
+ //#endregion
63
+ export { WorkspacePackage as n, isNodeError as r, PackageGraph as t };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "tegami",
3
+ "version": "0.0.0",
4
+ "description": "Utility for package versioning & publish",
5
+ "license": "MIT",
6
+ "author": "Fuma Nama",
7
+ "repository": "github:fuma-nama/tegami",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "type": "module",
12
+ "exports": {
13
+ ".": "./dist/index.mjs",
14
+ "./generators/simple": "./dist/generators/simple.mjs",
15
+ "./plugins/git": "./dist/plugins/git.mjs",
16
+ "./plugins/github": "./dist/plugins/github.mjs",
17
+ "./providers/cargo": "./dist/providers/cargo.mjs",
18
+ "./providers/npm": "./dist/providers/npm.mjs",
19
+ "./package.json": "./package.json"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "scripts": {
25
+ "types:check": "tsc --noEmit",
26
+ "build": "tsdown",
27
+ "dev": "tsdown --watch"
28
+ },
29
+ "dependencies": {
30
+ "js-yaml": "^4.2.0",
31
+ "mdast-util-from-markdown": "^2.0.3",
32
+ "mdast-util-to-markdown": "^2.1.2",
33
+ "package-manager-detector": "^1.6.0",
34
+ "semver": "^7.8.4",
35
+ "smol-toml": "^1.6.1",
36
+ "tinyexec": "^1.2.4",
37
+ "tinyglobby": "^0.2.17",
38
+ "zod": "^4.4.3"
39
+ },
40
+ "devDependencies": {
41
+ "@repo/typescript-config": "workspace:*",
42
+ "@types/js-yaml": "^4.0.9",
43
+ "@types/mdast": "^4.0.4",
44
+ "@types/node": "^25.5.0",
45
+ "@types/semver": "^7.7.1",
46
+ "tsdown": "^0.22.2",
47
+ "typescript": "6.0.3"
48
+ }
49
+ }