@theholocron/semantic-release-config 8.9.0-alpha.1 → 8.9.0-alpha.16

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/README.md CHANGED
@@ -51,6 +51,20 @@ export default defineConfig();
51
51
  | `exec` | `{ prepareCmd?, publishCmd? }` | `undefined` | Commands for `@semantic-release/exec`. Omit if not needed. |
52
52
  | `assets` | `string[]` | `['CHANGELOG.md', 'package.json', 'packages/*/package.json']` | Files committed by `@semantic-release/git` after release. |
53
53
 
54
+ ## Releasing a version group
55
+
56
+ A monorepo that releases several folders on their own lines uses `groupReleaseConfig()`. It builds on `defineConfig()` (same rules, notes and plugin order) and takes the same options plus a `group`: tags are `<group>-v<version>`, the analyzer and notes generator see only commits that touched the group's `paths` (default `[group]`), and the changelog, release commit assets and message are the group's.
57
+
58
+ ```js
59
+ import { groupReleaseConfig, ungroupedReleaseConfig } from "@theholocron/semantic-release-config";
60
+
61
+ export default process.env.RELEASE_GROUP
62
+ ? groupReleaseConfig({ group: process.env.RELEASE_GROUP, branches: ["main"] })
63
+ : ungroupedReleaseConfig({ groups: ["clients"], branches: ["main"] });
64
+ ```
65
+
66
+ `ungroupedReleaseConfig()` is the mirror for everything in no group: it skips commits confined to the `groups` folders. `folderScoped`, `ungroupedScoped`, `commitFiles` and `inScope` are exported too.
67
+
54
68
  ## Plugin pipeline
55
69
 
56
70
  The config wires up this fixed plugin order:
@@ -60,7 +74,7 @@ The config wires up this fixed plugin order:
60
74
  3. `@semantic-release/changelog` — writes `CHANGELOG.md`
61
75
  4. `@semantic-release/exec` — repo-specific version bump and publish commands _(only when `exec` is passed)_
62
76
  5. `@semantic-release/git` — commits updated files back to the repo
63
- 6. `@semantic-release/github` — creates a GitHub release
77
+ 6. `@semantic-release/github` — creates a GitHub release, and labels the issues and pull requests it ships `released` on every branch (the plugin's default is `released on @<channel>` on a prerelease branch)
64
78
 
65
79
  ## Named exports
66
80
 
package/dist/index.d.ts CHANGED
@@ -1,3 +1,12 @@
1
+ /** Runs `git` with `args` in `cwd`, feeding it `input` on stdin, and returns stdout. */
2
+ export type GitRun = (args: string[], input: string, cwd: string) => string;
3
+ /**
4
+ * The repo-relative files each of `hashes` changed, from one
5
+ * `git diff-tree --stdin` call. A commit that changes nothing (or a merge
6
+ * commit) maps to `[]`. Paths come back verbatim, not quoted, whatever they
7
+ * contain.
8
+ */
9
+ export declare function commitFiles(cwd: string, hashes: readonly string[], run?: GitRun): Map<string, string[]>;
1
10
  interface ExecOptions {
2
11
  prepareCmd?: string;
3
12
  publishCmd?: string;
@@ -13,6 +22,7 @@ interface Options {
13
22
  npm?: boolean | NpmOptions;
14
23
  assets?: string[];
15
24
  }
25
+ /** The `@semantic-release/commit-analyzer` plugin with the Conventional Commits preset: `feat` releases a minor, `fix`, `perf`, `refactor` and `chore(deps)` a patch, and a breaking change a major. */
16
26
  export declare const commitAnalyzer: (string | {
17
27
  preset: string;
18
28
  releaseRules: ({
@@ -32,6 +42,7 @@ export declare const commitAnalyzer: (string | {
32
42
  scope?: undefined;
33
43
  })[];
34
44
  })[];
45
+ /** The `@semantic-release/release-notes-generator` plugin with the Conventional Commits preset, grouping commits into changelog sections by type. */
35
46
  export declare const releaseNotesGenerator: (string | {
36
47
  preset: string;
37
48
  presetConfig: {
@@ -50,4 +61,116 @@ export declare const releaseNotesGenerator: (string | {
50
61
  * @see https://semantic-release.gitbook.io/semantic-release/usage/configuration
51
62
  */
52
63
  export declare function defineConfig({ branches, exec, npm, assets }?: Options): object;
53
- export {};
64
+ /** The slice of a semantic-release commit this module reads. */
65
+ interface ReleaseCommit {
66
+ /** Full commit hash. */
67
+ hash: string;
68
+ [key: string]: unknown;
69
+ }
70
+ /** The slice of a semantic-release plugin context this module reads; everything else passes through untouched. */
71
+ interface ReleaseContext {
72
+ /** The directory semantic-release runs in: the repo being released. */
73
+ cwd?: string;
74
+ /** The commits analysed for this release. */
75
+ commits?: ReleaseCommit[];
76
+ [key: string]: unknown;
77
+ }
78
+ /** A semantic-release plugin step that looks at commits. */
79
+ type CommitStep = "analyzeCommits" | "generateNotes" | "success";
80
+ type StepFn = (pluginConfig: unknown, context: ReleaseContext) => unknown;
81
+ /** A plugin module that implements `Step`. */
82
+ type StepPlugin<Step extends CommitStep> = Partial<Record<Step, StepFn>>;
83
+ /** What the folder-scoped release plugin depends on, each replaceable in a test. */
84
+ interface FolderScopedDeps {
85
+ /**
86
+ * Loads a plugin module by specifier, resolved from `cwd` (the repo being released). Defaults to a
87
+ * dynamic `import()` of the module as `cwd` resolves it, which is how semantic-release loads its own plugins.
88
+ */
89
+ load?: (specifier: string, cwd: string) => Promise<unknown>;
90
+ /** Lists the files each commit changed. Defaults to `git diff-tree`. */
91
+ listFiles?: typeof commitFiles;
92
+ }
93
+ /**
94
+ * An inline semantic-release plugin that runs `step` of the stock plugin
95
+ * (`@semantic-release/commit-analyzer` for `analyzeCommits`,
96
+ * `@semantic-release/release-notes-generator` for `generateNotes`) over only
97
+ * the commits that changed a file at or under `paths`.
98
+ *
99
+ * After a monorepo import, `lastTag..HEAD` spans every folder's commits, so an
100
+ * unscoped analyzer would release a folder for a commit that never touched it.
101
+ * The wrapped plugin is loaded on first use, so it only needs to be installed
102
+ * where a release actually runs. Commits are listed with one `git diff-tree`
103
+ * call, in `context.cwd`.
104
+ */
105
+ export declare function folderScoped<Step extends CommitStep>(step: Step, paths: readonly string[], deps?: FolderScopedDeps): StepPlugin<Step>;
106
+ /**
107
+ * The mirror of {@link folderScoped}, for the release of everything that is in **no**
108
+ * version group: it sees only commits that changed a file outside every group folder. A commit
109
+ * confined to a group (and the group's imported history) belongs to that group's release; letting the
110
+ * repo-wide one analyze it would release the repo for a change that is not in it, and write the
111
+ * group's commits into the repo's changelog.
112
+ */
113
+ export declare function ungroupedScoped<Step extends CommitStep>(step: Step, groups: readonly string[], deps?: FolderScopedDeps): StepPlugin<Step>;
114
+ /** The file `specifier` resolves to for the repo at `cwd`, else for `semantic-release`; `requireFrom` is a seam for tests. */
115
+ export declare function resolvePlugin(specifier: string, cwd: string, requireFrom?: (file: string) => {
116
+ resolve(id: string): string;
117
+ }): string;
118
+ /**
119
+ * Splits the GitHub plugin's entry so its "released in…" comments and labels go only to the PRs and
120
+ * issues of the commits `scoped` keeps. The entry stays as it was, so it still publishes the GitHub
121
+ * release, but with the commenting turned off; `scoped` (a {@link folderScoped} or
122
+ * {@link ungroupedScoped} `success` step) then does the commenting with the entry's own config.
123
+ */
124
+ export declare function commentOnlyFor(entry: string | [string, Record<string, unknown> | undefined], scoped: StepPlugin<"success">): ((string | [string, Record<string, unknown> | undefined]) | [object, unknown])[];
125
+ /** What `defineConfig()` from `@theholocron/semantic-release-config` accepts. */
126
+ type DefineConfigOptions = NonNullable<Parameters<typeof defineConfig>[0]>;
127
+ interface GroupReleaseOptions extends DefineConfigOptions {
128
+ /**
129
+ * The version group: a folder of the repo (`clients`, `observability`, `cli`) that
130
+ * releases on its own. It prefixes the tags (`clients-v1.43.2`) and the release commit.
131
+ */
132
+ group: string;
133
+ /** Repo-relative folders whose commits release this group. Defaults to `[group]`. */
134
+ paths?: readonly string[];
135
+ /** The group's changelog. Defaults to `<group>/CHANGELOG.md`. */
136
+ changelogFile?: string;
137
+ }
138
+ /**
139
+ * A semantic-release config that releases one version group of a monorepo,
140
+ * built on the org's `defineConfig()` so its rules, notes layout and plugin
141
+ * order stay the same:
142
+ *
143
+ * - tags are `<group>-v<version>`, so each group finds its own last release;
144
+ * - the commit analyzer and notes generator see only commits that touched the
145
+ * group's `paths` ({@link folderScoped});
146
+ * - the changelog, the release commit's assets and its message are the group's.
147
+ *
148
+ * Run one `semantic-release` per group. Cross-group dependencies resolve from
149
+ * the registry, so `paths` is the group's folder unless more is listed.
150
+ */
151
+ export declare function groupReleaseConfig(options: GroupReleaseOptions): object;
152
+ /**
153
+ * Whether any of `files` (repo-relative, `/`-separated) sits at or under one of
154
+ * `paths` (repo-relative folders). `clients` matches `clients/http/x.ts` but
155
+ * not `clients-old/x.ts`.
156
+ */
157
+ export declare function inScope(files: readonly string[], paths: readonly string[]): boolean;
158
+ /**
159
+ * Whether any of `files` sits **outside** every one of `folders`: the mirror of
160
+ * {@link inScope}. A commit that only touches the version groups' folders is out;
161
+ * one that touches anything else, even beside a group's files, is in.
162
+ */
163
+ export declare function outsideFolders(files: readonly string[], folders: readonly string[]): boolean;
164
+ interface UngroupedReleaseOptions extends DefineConfigOptions {
165
+ /** The version groups released on their own: folders of the repo whose commits this release ignores. */
166
+ groups: readonly string[];
167
+ }
168
+ /**
169
+ * The semantic-release config for everything that is in no version group, built on the org's
170
+ * `defineConfig()`: tags, changelog and release commit are the repo's own, as before. The commit
171
+ * analyzer and notes generator skip commits confined to the `groups` folders, because those
172
+ * belong to the groups' releases ({@link ungroupedScoped}). With no groups it is `defineConfig()`
173
+ * unchanged.
174
+ */
175
+ export declare function ungroupedReleaseConfig({ groups, ...options }: UngroupedReleaseOptions): object;
176
+ export type { CommitStep, DefineConfigOptions, FolderScopedDeps, GroupReleaseOptions, ReleaseCommit, ReleaseContext, StepPlugin, UngroupedReleaseOptions };
package/dist/index.js CHANGED
@@ -1,4 +1,42 @@
1
- // index.ts
1
+ import { createRequire } from "node:module";
2
+ import { execFileSync } from "node:child_process";
3
+ import { join } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ // commit-files/commit-files.ts
6
+ const defaultGitRun = (args, input, cwd) => execFileSync("git", args, {
7
+ cwd,
8
+ input,
9
+ encoding: "utf8",
10
+ maxBuffer: 268435456
11
+ });
12
+ /**
13
+ * The repo-relative files each of `hashes` changed, from one
14
+ * `git diff-tree --stdin` call. A commit that changes nothing (or a merge
15
+ * commit) maps to `[]`. Paths come back verbatim, not quoted, whatever they
16
+ * contain.
17
+ */
18
+ function commitFiles(cwd, hashes, run = defaultGitRun) {
19
+ const files = new Map(hashes.map((hash) => [hash, []]));
20
+ if (hashes.length === 0) return files;
21
+ const out = run([
22
+ "-c",
23
+ "core.quotePath=false",
24
+ "diff-tree",
25
+ "--stdin",
26
+ "--name-only",
27
+ "-r",
28
+ "--root"
29
+ ], `${hashes.join("\n")}\n`, cwd);
30
+ let current;
31
+ for (const line of out.split("\n")) {
32
+ if (line === "") continue;
33
+ const known = files.get(line);
34
+ if (known) current = known;
35
+ else current?.push(line);
36
+ }
37
+ return files;
38
+ }
39
+ // define-config/define-config.ts
2
40
  const releaseRules = [
3
41
  {
4
42
  type: "feat",
@@ -64,10 +102,12 @@ const types = [
64
102
  hidden: true
65
103
  }
66
104
  ];
105
+ /** The `@semantic-release/commit-analyzer` plugin with the Conventional Commits preset: `feat` releases a minor, `fix`, `perf`, `refactor` and `chore(deps)` a patch, and a breaking change a major. */
67
106
  const commitAnalyzer = ["@semantic-release/commit-analyzer", {
68
107
  preset: "conventionalcommits",
69
108
  releaseRules
70
109
  }];
110
+ /** The `@semantic-release/release-notes-generator` plugin with the Conventional Commits preset, grouping commits into changelog sections by type. */
71
111
  const releaseNotesGenerator = ["@semantic-release/release-notes-generator", {
72
112
  preset: "conventionalcommits",
73
113
  presetConfig: { types }
@@ -97,8 +137,182 @@ function defineConfig({ branches = ["main"], exec, npm, assets } = {}) {
97
137
  assets: resolvedAssets,
98
138
  message: defaultMessage
99
139
  }],
100
- "@semantic-release/github"
140
+ ["@semantic-release/github", { releasedLabels: ["released"] }]
141
+ ]
142
+ };
143
+ }
144
+ // in-scope/in-scope.ts
145
+ /**
146
+ * Whether any of `files` (repo-relative, `/`-separated) sits at or under one of
147
+ * `paths` (repo-relative folders). `clients` matches `clients/http/x.ts` but
148
+ * not `clients-old/x.ts`.
149
+ */
150
+ function inScope(files, paths) {
151
+ const folders = paths.map((path) => path.replace(/^\.\//, "").replace(/\/+$/, ""));
152
+ return files.some((file) => folders.some((folder) => file === folder || file.startsWith(`${folder}/`)));
153
+ }
154
+ /**
155
+ * Whether any of `files` sits **outside** every one of `folders`: the mirror of
156
+ * {@link inScope}. A commit that only touches the version groups' folders is out;
157
+ * one that touches anything else, even beside a group's files, is in.
158
+ */
159
+ function outsideFolders(files, folders) {
160
+ const normalized = folders.map((folder) => folder.replace(/^\.\//, "").replace(/\/+$/, ""));
161
+ return files.some((file) => !normalized.some((folder) => file === folder || file.startsWith(`${folder}/`)));
162
+ }
163
+ // folder-scoped/folder-scoped.ts
164
+ /** The semantic-release plugin that implements each commit-reading step. `success` is the GitHub plugin's "released in…" comments. */
165
+ const MODULES = {
166
+ analyzeCommits: "@semantic-release/commit-analyzer",
167
+ generateNotes: "@semantic-release/release-notes-generator",
168
+ success: "@semantic-release/github"
169
+ };
170
+ /**
171
+ * An inline semantic-release plugin that runs `step` of the stock plugin
172
+ * (`@semantic-release/commit-analyzer` for `analyzeCommits`,
173
+ * `@semantic-release/release-notes-generator` for `generateNotes`) over only
174
+ * the commits that changed a file at or under `paths`.
175
+ *
176
+ * After a monorepo import, `lastTag..HEAD` spans every folder's commits, so an
177
+ * unscoped analyzer would release a folder for a commit that never touched it.
178
+ * The wrapped plugin is loaded on first use, so it only needs to be installed
179
+ * where a release actually runs. Commits are listed with one `git diff-tree`
180
+ * call, in `context.cwd`.
181
+ */
182
+ function folderScoped(step, paths, deps = {}) {
183
+ return scopedBy(step, (files) => inScope(files, paths), deps);
184
+ }
185
+ /**
186
+ * The mirror of {@link folderScoped}, for the release of everything that is in **no**
187
+ * version group: it sees only commits that changed a file outside every group folder. A commit
188
+ * confined to a group (and the group's imported history) belongs to that group's release; letting the
189
+ * repo-wide one analyze it would release the repo for a change that is not in it, and write the
190
+ * group's commits into the repo's changelog.
191
+ */
192
+ function ungroupedScoped(step, groups, deps = {}) {
193
+ return scopedBy(step, (files) => outsideFolders(files, groups), deps);
194
+ }
195
+ /**
196
+ * `import()` of `specifier` the way semantic-release finds its own plugins: as the repo at `cwd` resolves it,
197
+ * else as `semantic-release` does (the stock plugins are its dependencies, not the repo's). A bare `import()`
198
+ * would resolve from this file, inside astromech, where neither is visible.
199
+ */
200
+ function importFrom(specifier, cwd) {
201
+ return import(pathToFileURL(resolvePlugin(specifier, cwd)).href);
202
+ }
203
+ /** The file `specifier` resolves to for the repo at `cwd`, else for `semantic-release`; `requireFrom` is a seam for tests. */
204
+ function resolvePlugin(specifier, cwd, requireFrom = createRequire) {
205
+ const fromRepo = requireFrom(join(cwd, "package.json"));
206
+ try {
207
+ return fromRepo.resolve(specifier);
208
+ } catch {
209
+ return requireFrom(fromRepo.resolve("semantic-release")).resolve(specifier);
210
+ }
211
+ }
212
+ function scopedBy(step, keep, { load = importFrom, listFiles = commitFiles }) {
213
+ const scoped = async (pluginConfig, context) => {
214
+ const { commits = [], cwd = process.cwd() } = context;
215
+ const inner = await load(MODULES[step], cwd);
216
+ const files = listFiles(cwd, commits.map((commit) => commit.hash));
217
+ const kept = commits.filter((commit) => keep(files.get(commit.hash) ?? []));
218
+ return inner[step]?.(pluginConfig, {
219
+ ...context,
220
+ commits: kept
221
+ });
222
+ };
223
+ return { [step]: scoped };
224
+ }
225
+ /**
226
+ * Splits the GitHub plugin's entry so its "released in…" comments and labels go only to the PRs and
227
+ * issues of the commits `scoped` keeps. The entry stays as it was, so it still publishes the GitHub
228
+ * release, but with the commenting turned off; `scoped` (a {@link folderScoped} or
229
+ * {@link ungroupedScoped} `success` step) then does the commenting with the entry's own config.
230
+ */
231
+ function commentOnlyFor(entry, scoped) {
232
+ const [name, config] = Array.isArray(entry) ? entry : [entry, void 0];
233
+ return [[name, {
234
+ ...config,
235
+ successComment: false,
236
+ releasedLabels: false
237
+ }], [scoped, config]];
238
+ }
239
+ // group-release-config/group-release-config.ts
240
+ const GROUP = /^[a-z][a-z0-9-]*$/;
241
+ /**
242
+ * A semantic-release config that releases one version group of a monorepo,
243
+ * built on the org's `defineConfig()` so its rules, notes layout and plugin
244
+ * order stay the same:
245
+ *
246
+ * - tags are `<group>-v<version>`, so each group finds its own last release;
247
+ * - the commit analyzer and notes generator see only commits that touched the
248
+ * group's `paths` ({@link folderScoped});
249
+ * - the changelog, the release commit's assets and its message are the group's.
250
+ *
251
+ * Run one `semantic-release` per group. Cross-group dependencies resolve from
252
+ * the registry, so `paths` is the group's folder unless more is listed.
253
+ */
254
+ function groupReleaseConfig(options) {
255
+ const { group, paths = [group], changelogFile = `${group}/CHANGELOG.md`, assets, ...rest } = options;
256
+ if (!GROUP.test(group)) throw new TypeError(`release group must be a lowercase folder name like "clients", got ${JSON.stringify(group)}`);
257
+ if (paths.length === 0) throw new TypeError(`release group ${JSON.stringify(group)} needs at least one path`);
258
+ const base = defineConfig({
259
+ ...rest,
260
+ assets: assets ?? [
261
+ changelogFile,
262
+ `${group}/**/package.json`,
263
+ "!**/node_modules/**"
101
264
  ]
265
+ });
266
+ const scope = (entry) => {
267
+ const [name, config] = Array.isArray(entry) ? entry : [entry, void 0];
268
+ switch (name) {
269
+ case "@semantic-release/commit-analyzer": return [[folderScoped("analyzeCommits", paths), config]];
270
+ case "@semantic-release/release-notes-generator": return [[folderScoped("generateNotes", paths), config]];
271
+ case "@semantic-release/changelog": return [[name, {
272
+ ...config,
273
+ changelogFile
274
+ }]];
275
+ case "@semantic-release/git": return [[name, {
276
+ ...config,
277
+ message: groupMessage(config?.["message"], group)
278
+ }]];
279
+ case "@semantic-release/github": return commentOnlyFor(entry, folderScoped("success", paths));
280
+ default: return [entry];
281
+ }
282
+ };
283
+ return {
284
+ ...base,
285
+ tagFormat: `${group}-v\${version}`,
286
+ plugins: base.plugins.flatMap(scope)
287
+ };
288
+ }
289
+ /** `chore(release): <version> …` becomes `chore(release): <group> <version> …`. */
290
+ function groupMessage(message, group) {
291
+ return message.replace(/^chore\(release\): /, `chore(release): ${group} `);
292
+ }
293
+ // ungrouped-release-config/ungrouped-release-config.ts
294
+ /**
295
+ * The semantic-release config for everything that is in no version group, built on the org's
296
+ * `defineConfig()`: tags, changelog and release commit are the repo's own, as before. The commit
297
+ * analyzer and notes generator skip commits confined to the `groups` folders, because those
298
+ * belong to the groups' releases ({@link ungroupedScoped}). With no groups it is `defineConfig()`
299
+ * unchanged.
300
+ */
301
+ function ungroupedReleaseConfig({ groups, ...options }) {
302
+ const base = defineConfig(options);
303
+ if (groups.length === 0) return base;
304
+ const scope = (entry) => {
305
+ const [name, config] = Array.isArray(entry) ? entry : [entry, void 0];
306
+ switch (name) {
307
+ case "@semantic-release/commit-analyzer": return [[ungroupedScoped("analyzeCommits", groups), config]];
308
+ case "@semantic-release/release-notes-generator": return [[ungroupedScoped("generateNotes", groups), config]];
309
+ case "@semantic-release/github": return commentOnlyFor(entry, ungroupedScoped("success", groups));
310
+ default: return [entry];
311
+ }
312
+ };
313
+ return {
314
+ ...base,
315
+ plugins: base.plugins.flatMap(scope)
102
316
  };
103
317
  }
104
- export { commitAnalyzer, defineConfig, releaseNotesGenerator };
318
+ export { commentOnlyFor, commitAnalyzer, commitFiles, defineConfig, folderScoped, groupReleaseConfig, inScope, outsideFolders, releaseNotesGenerator, resolvePlugin, ungroupedReleaseConfig, ungroupedScoped };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theholocron/semantic-release-config",
3
- "version": "8.9.0-alpha.1",
3
+ "version": "8.9.0-alpha.16",
4
4
  "description": "A semantic-release configuration for automated versioning and publishing.",
5
5
  "keywords": [
6
6
  "semantic-release",
@@ -33,12 +33,15 @@
33
33
  "dist/"
34
34
  ],
35
35
  "devDependencies": {
36
- "@vitest/coverage-v8": "^5.0.5",
37
- "tsdown": "^0.23.3",
36
+ "@semantic-release/commit-analyzer": "^13.0.1",
37
+ "@semantic-release/release-notes-generator": "^14.1.1",
38
+ "@vitest/coverage-v8": "^5.1.0",
39
+ "conventional-changelog-conventionalcommits": "9.3.1",
40
+ "tsdown": "^0.23.5",
38
41
  "typescript": "^5.9.3",
39
- "vitest": "^5.0.5",
40
- "@theholocron/tsconfig": "8.9.0-alpha.1",
41
- "@theholocron/vitest-config": "8.9.0-alpha.1"
42
+ "vitest": "^5.1.0",
43
+ "@theholocron/tsconfig": "8.9.0-alpha.16",
44
+ "@theholocron/vitest-config": "8.9.0-alpha.16"
42
45
  },
43
46
  "peerDependencies": {
44
47
  "@semantic-release/changelog": "^6",
@@ -62,10 +65,10 @@
62
65
  "access": "public"
63
66
  },
64
67
  "scripts": {
65
- "delivery.build": "tsdown",
66
- "sourceQuality.staticAnalysis": "eslint .",
68
+ "build": "tsdown",
69
+ "lint:code": "eslint .",
70
+ "test:unit": "vitest run --coverage",
67
71
  "test:watch": "vitest",
68
- "verification.typeSafety": "tsc --noEmit",
69
- "verification.unitTests": "vitest run"
72
+ "typecheck": "tsc --noEmit"
70
73
  }
71
74
  }