tegami 0.0.1 → 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/checks-CKBRRjgQ.js +100 -0
- package/dist/cli/{index.d.mts → index.d.ts} +2 -2
- package/dist/cli/{index.mjs → index.js} +59 -46
- package/dist/error-DBK-9uBa.js +23 -0
- package/dist/generators/{simple.d.mts → simple.d.ts} +1 -1
- package/dist/generators/{simple.mjs → simple.js} +3 -3
- package/dist/graph-CUgwuRW5.js +107 -0
- package/dist/index-Bhh2dJZp.d.ts +460 -0
- package/dist/index.d.ts +2 -0
- package/dist/{index.mjs → index.js} +179 -194
- package/dist/plugins/{git.d.mts → git.d.ts} +1 -1
- package/dist/plugins/git.js +84 -0
- package/dist/plugins/{github.d.mts → github.d.ts} +23 -9
- package/dist/plugins/github.js +187 -0
- package/dist/providers/cargo.d.ts +2 -0
- package/dist/providers/{cargo.mjs → cargo.js} +110 -52
- package/dist/providers/npm.d.ts +2 -0
- package/dist/providers/npm.js +278 -0
- package/dist/schemas-Cc4h6bq5.js +41 -0
- package/dist/semver-mWK2Khi2.js +33 -0
- package/package.json +22 -22
- package/dist/context-CC36jtz1.d.mts +0 -297
- package/dist/exec-hOS852t5.mjs +0 -12
- package/dist/index-DJ7YxxdM.d.mts +0 -35
- package/dist/index.d.mts +0 -3
- package/dist/npm-BpFlXy8I.mjs +0 -281
- package/dist/plugins/git.mjs +0 -99
- package/dist/plugins/github.mjs +0 -146
- package/dist/providers/cargo.d.mts +0 -32
- package/dist/providers/npm.d.mts +0 -2
- package/dist/providers/npm.mjs +0 -2
- package/dist/semver-FSWx3_34.mjs +0 -35
- package/dist/workspace-B5_i21S0.mjs +0 -63
- /package/dist/{constants-B9qjNfvr.mjs → constants-B9qjNfvr.js} +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { n as handlePluginError } from "./error-DBK-9uBa.js";
|
|
2
|
+
import { n as jsonCodec } from "./schemas-Cc4h6bq5.js";
|
|
3
|
+
import z$1 from "zod";
|
|
4
|
+
import { readFile } from "fs/promises";
|
|
5
|
+
//#region src/plans/store.ts
|
|
6
|
+
const packagePlanStoreSchema = z$1.object({
|
|
7
|
+
type: z$1.enum([
|
|
8
|
+
"major",
|
|
9
|
+
"minor",
|
|
10
|
+
"patch"
|
|
11
|
+
]).optional(),
|
|
12
|
+
changelogIds: z$1.array(z$1.string()).optional(),
|
|
13
|
+
bumpReasons: z$1.array(z$1.string()).optional(),
|
|
14
|
+
npm: z$1.object({ distTag: z$1.string().optional() }).optional(),
|
|
15
|
+
publish: z$1.boolean()
|
|
16
|
+
});
|
|
17
|
+
/** the persisted plan data for actual publishing */
|
|
18
|
+
const planStoreSchema = jsonCodec(z$1.object({
|
|
19
|
+
id: z$1.string(),
|
|
20
|
+
createdAt: z$1.iso.datetime(),
|
|
21
|
+
version: z$1.literal("0.0.0").default("0.0.0"),
|
|
22
|
+
/** release note entries */
|
|
23
|
+
changelogs: z$1.record(z$1.string(), z$1.object({
|
|
24
|
+
filename: z$1.string(),
|
|
25
|
+
subject: z$1.string().optional(),
|
|
26
|
+
packages: z$1.array(z$1.string()),
|
|
27
|
+
type: z$1.enum([
|
|
28
|
+
"major",
|
|
29
|
+
"minor",
|
|
30
|
+
"patch"
|
|
31
|
+
]),
|
|
32
|
+
title: z$1.string(),
|
|
33
|
+
content: z$1.string()
|
|
34
|
+
})),
|
|
35
|
+
/** package id -> package info */
|
|
36
|
+
packages: z$1.record(z$1.string(), packagePlanStoreSchema)
|
|
37
|
+
}));
|
|
38
|
+
function createPlanStore(draft, context) {
|
|
39
|
+
const store = {
|
|
40
|
+
version: "0.0.0",
|
|
41
|
+
id: `tegami-${Date.now().toString(36)}`,
|
|
42
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
43
|
+
changelogs: {},
|
|
44
|
+
packages: {}
|
|
45
|
+
};
|
|
46
|
+
for (const entry of draft.getChangelogs()) store.changelogs[entry.id] = {
|
|
47
|
+
filename: entry.filename,
|
|
48
|
+
subject: entry.subject,
|
|
49
|
+
packages: Array.from(entry.packages),
|
|
50
|
+
type: entry.type,
|
|
51
|
+
title: entry.title,
|
|
52
|
+
content: entry.content
|
|
53
|
+
};
|
|
54
|
+
for (const pkg of context.graph.getPackages()) {
|
|
55
|
+
const plan = draft.getPackagePlan(pkg.id);
|
|
56
|
+
if (plan) store.packages[pkg.id] = {
|
|
57
|
+
publish: plan.publish ?? false,
|
|
58
|
+
type: plan.type,
|
|
59
|
+
npm: plan.npm,
|
|
60
|
+
changelogIds: plan.changelogs?.map((entry) => entry.id),
|
|
61
|
+
bumpReasons: plan.bumpReasons ? Array.from(plan.bumpReasons) : void 0
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return planStoreSchema.encode(store);
|
|
65
|
+
}
|
|
66
|
+
async function readPlanStore(context) {
|
|
67
|
+
try {
|
|
68
|
+
return planStoreSchema.decode(await readFile(context.planPath, "utf8"));
|
|
69
|
+
} catch {}
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region src/plans/checks.ts
|
|
73
|
+
async function publishPlanStatus(store, context) {
|
|
74
|
+
async function defaultStatus() {
|
|
75
|
+
try {
|
|
76
|
+
await Promise.all(Object.entries(store.packages).map(async ([id, plan]) => {
|
|
77
|
+
const pkg = context.graph.get(id);
|
|
78
|
+
if (!pkg || !plan.publish) return;
|
|
79
|
+
if (!await context.getRegistryClient(pkg).isPackagePublished(pkg)) throw "pending";
|
|
80
|
+
}));
|
|
81
|
+
return { state: "success" };
|
|
82
|
+
} catch (err) {
|
|
83
|
+
if (err === "pending") return { state: "pending" };
|
|
84
|
+
throw err;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
let status = await defaultStatus();
|
|
88
|
+
for (const plugin of context.plugins) {
|
|
89
|
+
const resolved = await handlePluginError(plugin, "resolvePlanStatus", () => plugin.resolvePlanStatus?.call(context, status, { plan: store }));
|
|
90
|
+
if (resolved) status = resolved;
|
|
91
|
+
}
|
|
92
|
+
return status;
|
|
93
|
+
}
|
|
94
|
+
async function assertPublishPlanFinished(context) {
|
|
95
|
+
const store = await readPlanStore(context);
|
|
96
|
+
if (!store) return;
|
|
97
|
+
if ((await publishPlanStatus(store, context)).state === "pending") throw new Error(`Publish plan already exists at ${context.planPath} and is pending. Publish it before applying a new plan.`);
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
export { readPlanStore as i, publishPlanStatus as n, createPlanStore as r, assertPublishPlanFinished as t };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as Tegami } from "../index-DJ7YxxdM.mjs";
|
|
1
|
+
import { C as PublishResult, a as Awaitable, t as Tegami, w as DraftPlan } from "../index-Bhh2dJZp.js";
|
|
3
2
|
import { Command } from "commander";
|
|
4
3
|
|
|
5
4
|
//#region src/cli/index.d.ts
|
|
6
5
|
interface TegamiCLIOptions {
|
|
6
|
+
/** create a custom draft plan, it must not be applied */
|
|
7
7
|
version?: () => Awaitable<DraftPlan>;
|
|
8
8
|
publish?: () => Awaitable<PublishResult>;
|
|
9
9
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as handlePluginError } from "../error-DBK-9uBa.js";
|
|
2
|
+
import { t as assertPublishPlanFinished } from "../checks-CKBRRjgQ.js";
|
|
3
|
+
import { t as isCI } from "../constants-B9qjNfvr.js";
|
|
2
4
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
-
import { join
|
|
5
|
+
import { join } from "node:path";
|
|
4
6
|
import { confirm, intro, isCancel, multiselect, note, outro, select, spinner, text } from "@clack/prompts";
|
|
5
7
|
import { Command } from "commander";
|
|
6
8
|
//#region src/cli/index.ts
|
|
@@ -11,24 +13,26 @@ var CancelledError = class extends Error {
|
|
|
11
13
|
};
|
|
12
14
|
function createCli(tegami, options = {}) {
|
|
13
15
|
const program = new Command();
|
|
14
|
-
program.name("tegami").description("
|
|
16
|
+
program.name("tegami").description("create changelogs").action((commandOptions) => runAction(tegami, () => createChangelogs(tegami, {
|
|
15
17
|
...commandOptions,
|
|
16
18
|
cli: options
|
|
17
19
|
})));
|
|
18
|
-
program.command("version").description("
|
|
20
|
+
program.command("version").description("draft and apply a publish plan").action((commandOptions) => runAction(tegami, () => versionPackages(tegami, {
|
|
19
21
|
...commandOptions,
|
|
20
22
|
cli: options
|
|
21
23
|
})));
|
|
22
|
-
program.command("publish").description("publish packages from the
|
|
24
|
+
program.command("publish").description("publish packages from the applied publish plan").option("--dry-run", "validate the publish plan without publishing packages").action((commandOptions) => runAction(tegami, () => publishPackages(tegami, {
|
|
23
25
|
...commandOptions,
|
|
24
26
|
cli: options
|
|
25
27
|
})));
|
|
28
|
+
program.command("cleanup").description("remove the publish plan after all packages have been published").action(() => runAction(tegami, () => runCleanup(tegami)));
|
|
26
29
|
return program;
|
|
27
30
|
}
|
|
28
31
|
async function createChangelogs(tegami, _options) {
|
|
32
|
+
const context = await tegami._internal.context();
|
|
33
|
+
await assertPublishPlanFinished(context);
|
|
29
34
|
intro("Create changelogs");
|
|
30
|
-
const
|
|
31
|
-
const packages = graph.getPackages();
|
|
35
|
+
const packages = context.graph.getPackages();
|
|
32
36
|
let selectedPackages = [];
|
|
33
37
|
if (isCI()) selectedPackages = [];
|
|
34
38
|
else {
|
|
@@ -92,11 +96,10 @@ async function createChangelogs(tegami, _options) {
|
|
|
92
96
|
});
|
|
93
97
|
if (isCancel(message)) throw new CancelledError();
|
|
94
98
|
const filename = changelogFilename();
|
|
95
|
-
const directory = resolve(cwd, changelogDir);
|
|
96
99
|
const s = spinner();
|
|
97
100
|
s.start("Creating changelog");
|
|
98
|
-
await mkdir(
|
|
99
|
-
await writeFile(join(
|
|
101
|
+
await mkdir(context.changelogDir, { recursive: true });
|
|
102
|
+
await writeFile(join(context.changelogDir, filename), renderManualChangelog(selectedPackages, type, message.trim()));
|
|
100
103
|
s.stop("Created changelog file");
|
|
101
104
|
note(`${filename}\n${selectedPackages.join(", ")}: ${type}`, "Created changelog");
|
|
102
105
|
outro("Changelog ready.");
|
|
@@ -104,36 +107,34 @@ async function createChangelogs(tegami, _options) {
|
|
|
104
107
|
async function versionPackages(tegami, options) {
|
|
105
108
|
intro("Version Packages");
|
|
106
109
|
const { version: customVersion } = options.cli;
|
|
110
|
+
const context = await tegami._internal.context();
|
|
107
111
|
const draft = customVersion ? await customVersion() : await tegami.draft();
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
if (!draft.canApply()) throw new Error(`The draft plan from custom "version" hook must not be applied`);
|
|
113
|
+
for (const plugin of context.plugins) await handlePluginError(plugin, "cli.publishPlanCreated", () => plugin.cli?.publishPlanCreated?.call(context, draft));
|
|
114
|
+
if (!draft.hasPending()) {
|
|
110
115
|
note("No pending changelog entries matched workspace packages.", "Nothing to version");
|
|
111
116
|
outro("No versions changed.");
|
|
112
117
|
return;
|
|
113
118
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
s.start("Updating package versions");
|
|
121
|
-
try {
|
|
122
|
-
await draft.createPublishPlan();
|
|
123
|
-
} catch (error) {
|
|
124
|
-
s.stop("Failed to create publish plan");
|
|
125
|
-
throw error;
|
|
126
|
-
}
|
|
127
|
-
s.stop("Package versions updated");
|
|
119
|
+
const planEntries = [];
|
|
120
|
+
for (const pkg of context.graph.getPackages()) {
|
|
121
|
+
const plan = draft.getPackagePlan(pkg.id);
|
|
122
|
+
if (!plan?.type) continue;
|
|
123
|
+
planEntries.push(`${pkg.id}: ${plan.type} (${plan.changelogs?.length ?? 0} changelogs)`);
|
|
124
|
+
if (plan.bumpReasons) for (const reason of plan.bumpReasons) planEntries.push(` - ${reason}`);
|
|
128
125
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
note(planEntries.join("\n"), "Release plan");
|
|
127
|
+
const s = spinner();
|
|
128
|
+
s.start("Updating package versions");
|
|
129
|
+
try {
|
|
130
|
+
await draft.applyPlan();
|
|
132
131
|
} catch (error) {
|
|
133
|
-
|
|
134
|
-
throw
|
|
132
|
+
s.stop("Failed to apply publish plan");
|
|
133
|
+
throw error;
|
|
135
134
|
}
|
|
136
|
-
|
|
135
|
+
s.stop("Package versions updated");
|
|
136
|
+
for (const plugin of context.plugins) await handlePluginError(plugin, "cli.publishPlanApplied", () => plugin.cli?.publishPlanApplied?.call(context, draft));
|
|
137
|
+
outro("Publish plan applied.");
|
|
137
138
|
}
|
|
138
139
|
async function publishPackages(tegami, options) {
|
|
139
140
|
const dryRun = options.dryRun ?? false;
|
|
@@ -143,13 +144,14 @@ async function publishPackages(tegami, options) {
|
|
|
143
144
|
s.start(dryRun ? "Validating publish plan" : "Publishing packages");
|
|
144
145
|
const result = customPublish ? await customPublish() : await tegami.publish({ dryRun });
|
|
145
146
|
if (result.state === "skipped") {
|
|
147
|
+
const { planPath } = await tegami._internal.context();
|
|
146
148
|
s.stop(dryRun ? "No publish plan to validate" : "Nothing to publish");
|
|
147
|
-
outro(`No publishable packages were found in ${
|
|
149
|
+
outro(`No publishable packages were found in ${planPath}.`);
|
|
148
150
|
return;
|
|
149
151
|
}
|
|
150
152
|
s.stop(dryRun ? "Publish plan validated" : "Publish complete");
|
|
151
153
|
note(result.packages.map((pkg) => {
|
|
152
|
-
const tag = pkg.distTag ? ` (${pkg.distTag})` : "";
|
|
154
|
+
const tag = pkg.npm?.distTag ? ` (${pkg.npm.distTag})` : "";
|
|
153
155
|
const suffix = pkg.state === "failed" && pkg.error ? `: ${pkg.error}` : "";
|
|
154
156
|
return `${pkg.state === "success" ? "success" : "failed"} ${pkg.name}@${pkg.version}${tag}${suffix}`;
|
|
155
157
|
}).join("\n"), dryRun ? "Publish dry run" : "Publish result");
|
|
@@ -160,6 +162,23 @@ async function publishPackages(tegami, options) {
|
|
|
160
162
|
}
|
|
161
163
|
outro(dryRun ? "Publish plan is valid." : "Packages published.");
|
|
162
164
|
}
|
|
165
|
+
async function runCleanup(tegami) {
|
|
166
|
+
intro("Cleanup publish plan");
|
|
167
|
+
const s = spinner();
|
|
168
|
+
s.start("Checking publish plan status");
|
|
169
|
+
const result = await tegami.cleanup();
|
|
170
|
+
const { planPath } = await tegami._internal.context();
|
|
171
|
+
s.stop(result.state === "removed" ? "Publish plan removed" : "Publish plan kept");
|
|
172
|
+
if (result.state === "removed") {
|
|
173
|
+
outro(`Removed ${planPath}.`);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (result.reason === "missing") {
|
|
177
|
+
outro(`No publish plan found at ${planPath}.`);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
outro(`Publish plan at ${planPath} is still pending. Publish it before cleanup.`);
|
|
181
|
+
}
|
|
163
182
|
function renderManualChangelog(packages, type, message) {
|
|
164
183
|
const heading = "#".repeat(type === "major" ? 1 : type === "minor" ? 2 : 3);
|
|
165
184
|
return [
|
|
@@ -178,21 +197,15 @@ function changelogFilename() {
|
|
|
178
197
|
async function runAction(tegami, action) {
|
|
179
198
|
try {
|
|
180
199
|
const context = await tegami._internal.context();
|
|
181
|
-
for (const plugin of context.plugins)
|
|
182
|
-
await plugin.cli?.init?.call(context);
|
|
183
|
-
} catch (error) {
|
|
184
|
-
const details = error instanceof Error ? error.message : String(error);
|
|
185
|
-
throw new Error(`Plugin "${plugin.name}" failed during cli.init:\n${details}`, { cause: error });
|
|
186
|
-
}
|
|
200
|
+
for (const plugin of context.plugins) await handlePluginError(plugin, "cli.init", () => plugin.cli?.init?.call(context));
|
|
187
201
|
await action();
|
|
188
202
|
} catch (error) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
203
|
+
if (error instanceof CancelledError) outro(error.message);
|
|
204
|
+
else {
|
|
205
|
+
note(error instanceof Error ? error.message : String(error), "Error");
|
|
206
|
+
outro("Command failed.");
|
|
193
207
|
}
|
|
194
|
-
|
|
195
|
-
outro("Command failed.");
|
|
208
|
+
process.exit(1);
|
|
196
209
|
}
|
|
197
210
|
}
|
|
198
211
|
//#endregion
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/utils/error.ts
|
|
2
|
+
function commandOutput(result) {
|
|
3
|
+
return [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
|
|
4
|
+
}
|
|
5
|
+
function execFailure(context, result) {
|
|
6
|
+
const lines = [context, `(exit ${result.exitCode})`];
|
|
7
|
+
const output = commandOutput(result);
|
|
8
|
+
if (output) lines.push(output);
|
|
9
|
+
return new Error(lines.join("\n"));
|
|
10
|
+
}
|
|
11
|
+
function isNodeError(error) {
|
|
12
|
+
return error instanceof Error && "code" in error;
|
|
13
|
+
}
|
|
14
|
+
async function handlePluginError(plugin, hookName, callback) {
|
|
15
|
+
try {
|
|
16
|
+
return await callback();
|
|
17
|
+
} catch (error) {
|
|
18
|
+
const details = error instanceof Error ? error.message : String(error);
|
|
19
|
+
throw new Error(`Plugin "${plugin.name}" failed during ${hookName}:\n${details}`, { cause: error });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { handlePluginError as n, isNodeError as r, execFailure as t };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as formatPackageVersion } from "../semver-mWK2Khi2.js";
|
|
2
2
|
//#region src/generators/simple.ts
|
|
3
3
|
function simpleGenerator() {
|
|
4
|
-
return { generate({ changelogs, version, packageName,
|
|
4
|
+
return { generate({ changelogs, version, packageName, plan }) {
|
|
5
5
|
return [
|
|
6
|
-
`## ${formatPackageVersion(packageName, version, distTag)}`,
|
|
6
|
+
`## ${formatPackageVersion(packageName, version, plan.npm?.distTag)}`,
|
|
7
7
|
"",
|
|
8
8
|
...changelogs.flatMap((entry) => [
|
|
9
9
|
`### ${entry.title}`,
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { t as bumpVersion } from "./semver-mWK2Khi2.js";
|
|
2
|
+
//#region src/graph.ts
|
|
3
|
+
/** Package discovered in the workspace. */
|
|
4
|
+
var WorkspacePackage = class {
|
|
5
|
+
get id() {
|
|
6
|
+
return `${this.manager}:${this.name}`;
|
|
7
|
+
}
|
|
8
|
+
opts = {};
|
|
9
|
+
/** note: this will only be available after package graph is resolved */
|
|
10
|
+
getPackageOptions() {
|
|
11
|
+
return this.opts;
|
|
12
|
+
}
|
|
13
|
+
setPackageOptions(options) {
|
|
14
|
+
this.opts = options;
|
|
15
|
+
}
|
|
16
|
+
/** create an empty draft plan. */
|
|
17
|
+
onPlan(_context) {
|
|
18
|
+
const { publish, prerelease, npm } = this.opts;
|
|
19
|
+
return {
|
|
20
|
+
publish,
|
|
21
|
+
prerelease,
|
|
22
|
+
npm: npm ? { distTag: npm.distTag } : void 0,
|
|
23
|
+
bumpVersion(pkg) {
|
|
24
|
+
return bumpVersion(pkg.version, this.type, this.prerelease);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
/** Dependency graph for discovered workspace packages. */
|
|
30
|
+
var PackageGraph = class {
|
|
31
|
+
packages = /* @__PURE__ */ new Map();
|
|
32
|
+
groups = /* @__PURE__ */ new Map();
|
|
33
|
+
constructor(packages = []) {
|
|
34
|
+
for (const pkg of packages) this.add(pkg);
|
|
35
|
+
}
|
|
36
|
+
getPackages() {
|
|
37
|
+
const out = [];
|
|
38
|
+
for (const pkg of this.packages.values()) out.push(pkg.value);
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
/** Get a package by exact id. */
|
|
42
|
+
get(id) {
|
|
43
|
+
return this.packages.get(id)?.value;
|
|
44
|
+
}
|
|
45
|
+
/** Get packages by id, `group:name`, or every package matching a name. */
|
|
46
|
+
getByName(nameOrId) {
|
|
47
|
+
const exact = this.packages.get(nameOrId);
|
|
48
|
+
if (exact) return [exact.value];
|
|
49
|
+
if (nameOrId.startsWith("group:")) return this.getGroup(nameOrId.slice(6))?.packages ?? [];
|
|
50
|
+
const out = [];
|
|
51
|
+
for (const { value } of this.packages.values()) if (value.name === nameOrId) out.push(value);
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
/** scan package into graph, if the package id already exists, replace the existing one in graph */
|
|
55
|
+
add(pkg) {
|
|
56
|
+
this.delete(pkg.id);
|
|
57
|
+
this.packages.set(pkg.id, { value: pkg });
|
|
58
|
+
}
|
|
59
|
+
delete(id) {
|
|
60
|
+
this.packages.delete(id);
|
|
61
|
+
for (const group of this.groups.values()) {
|
|
62
|
+
const index = group.packages.findIndex((pkg) => pkg.id === id);
|
|
63
|
+
if (index >= 0) group.packages.splice(index, 1);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
getPackageGroup(pkgId) {
|
|
67
|
+
return this.packages.get(pkgId)?.group;
|
|
68
|
+
}
|
|
69
|
+
getGroups() {
|
|
70
|
+
return Array.from(this.groups.values());
|
|
71
|
+
}
|
|
72
|
+
getGroup(name) {
|
|
73
|
+
return this.groups.get(name);
|
|
74
|
+
}
|
|
75
|
+
registerGroup(name, options) {
|
|
76
|
+
const existing = this.groups.get(name);
|
|
77
|
+
if (existing) {
|
|
78
|
+
existing.options = options;
|
|
79
|
+
return existing;
|
|
80
|
+
}
|
|
81
|
+
const group = {
|
|
82
|
+
name,
|
|
83
|
+
options,
|
|
84
|
+
packages: []
|
|
85
|
+
};
|
|
86
|
+
this.groups.set(name, group);
|
|
87
|
+
return group;
|
|
88
|
+
}
|
|
89
|
+
addGroupMember(groupId, id) {
|
|
90
|
+
const group = this.groups.get(groupId);
|
|
91
|
+
const pkg = this.packages.get(id);
|
|
92
|
+
if (!group || !pkg || pkg.group) return;
|
|
93
|
+
pkg.group = group;
|
|
94
|
+
group.packages.push(pkg.value);
|
|
95
|
+
}
|
|
96
|
+
removeGroupMember(group, id) {
|
|
97
|
+
const entry = this.groups.get(group);
|
|
98
|
+
if (!entry) return;
|
|
99
|
+
const index = entry.packages.findIndex((pkg) => pkg.id === id);
|
|
100
|
+
if (index >= 0) entry.packages.splice(index, 1);
|
|
101
|
+
}
|
|
102
|
+
unregisterGroup(name) {
|
|
103
|
+
this.groups.delete(name);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
//#endregion
|
|
107
|
+
export { WorkspacePackage as n, PackageGraph as t };
|