@savvy-web/silk-effects 0.1.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/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { BiomeSchemaSync, BiomeSchemaSyncLive, BiomeSyncError } from "./biome.js";
2
+ export { ChangesetConfigError, ChangesetConfigReader, ChangesetConfigReaderLive, VersioningDetectionError, VersioningStrategy, VersioningStrategyLive } from "./versioning.js";
3
+ export { ConfigDiscovery, ConfigDiscoveryLive, ConfigNotFoundError } from "./config.js";
4
+ export { ManagedSection, ManagedSectionLive, ManagedSectionParseError, ManagedSectionWriteError } from "./hooks.js";
5
+ export { PublishConfigError, SilkPublishabilityPlugin, SilkPublishabilityPluginLive, TargetResolutionError, TargetResolver, TargetResolverLive } from "./publish.js";
6
+ export { TagFormatError, TagStrategy, TagStrategyLive } from "./tags.js";
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@savvy-web/silk-effects",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "description": "Shared Effect library for Silk Suite conventions",
6
+ "homepage": "https://github.com/savvy-web/systems/tree/main/packages/silk-effects",
7
+ "bugs": {
8
+ "url": "https://github.com/savvy-web/systems/issues"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/savvy-web/systems.git",
13
+ "directory": "packages/silk-effects"
14
+ },
15
+ "license": "MIT",
16
+ "author": {
17
+ "name": "C. Spencer Beggs",
18
+ "email": "spencer@savvyweb.systems",
19
+ "url": "https://savvyweb.systems"
20
+ },
21
+ "sideEffects": false,
22
+ "type": "module",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./index.d.ts",
26
+ "import": "./index.js"
27
+ },
28
+ "./publish": {
29
+ "types": "./publish.d.ts",
30
+ "import": "./publish.js"
31
+ },
32
+ "./versioning": {
33
+ "types": "./versioning.d.ts",
34
+ "import": "./versioning.js"
35
+ },
36
+ "./tags": {
37
+ "types": "./tags.d.ts",
38
+ "import": "./tags.js"
39
+ },
40
+ "./hooks": {
41
+ "types": "./hooks.d.ts",
42
+ "import": "./hooks.js"
43
+ },
44
+ "./config": {
45
+ "types": "./config.d.ts",
46
+ "import": "./config.js"
47
+ },
48
+ "./biome": {
49
+ "types": "./biome.d.ts",
50
+ "import": "./biome.js"
51
+ }
52
+ },
53
+ "dependencies": {
54
+ "@effect/platform": "^0.96.0",
55
+ "jsonc-effect": "^0.2.1",
56
+ "semver-effect": "^0.2.1",
57
+ "workspaces-effect": "^0.1.0",
58
+ "yaml-effect": "^0.2.3"
59
+ },
60
+ "peerDependencies": {
61
+ "effect": ">=3.21.0"
62
+ },
63
+ "files": [
64
+ "!silk-effects.api.json",
65
+ "!tsconfig.json",
66
+ "!tsdoc.json",
67
+ "LICENSE",
68
+ "README.md",
69
+ "biome.d.ts",
70
+ "biome.js",
71
+ "config.d.ts",
72
+ "config.js",
73
+ "hooks.d.ts",
74
+ "hooks.js",
75
+ "index.d.ts",
76
+ "index.js",
77
+ "package.json",
78
+ "publish.d.ts",
79
+ "publish.js",
80
+ "tags.d.ts",
81
+ "tags.js",
82
+ "tsdoc-metadata.json",
83
+ "versioning.d.ts",
84
+ "versioning.js"
85
+ ]
86
+ }
package/publish.d.ts ADDED
@@ -0,0 +1,260 @@
1
+ import { Context } from 'effect';
2
+ import { Effect } from 'effect';
3
+ import { Layer } from 'effect';
4
+ import { Schema } from 'effect';
5
+ import { VoidIfEmpty } from 'effect/Types';
6
+ import { YieldableError } from 'effect/Cause';
7
+
8
+ /**
9
+ * Authentication strategy used to obtain publish credentials.
10
+ *
11
+ * @remarks
12
+ * `"oidc"` relies on GitHub Actions OIDC provenance tokens (no explicit secret needed).
13
+ * `"token"` reads a long-lived token from an environment variable.
14
+ *
15
+ * @since 0.1.0
16
+ */
17
+ export declare const AuthStrategy: Schema.Literal<["oidc", "token"]>;
18
+
19
+ /** @since 0.1.0 */
20
+ export declare type AuthStrategy = typeof AuthStrategy.Type;
21
+
22
+ /**
23
+ * Raised when the `publishConfig` field in a `package.json` is present but invalid.
24
+ *
25
+ * @remarks
26
+ * Returned by {@link SilkPublishabilityPlugin.detect} when `publishConfig` exists
27
+ * but cannot be mapped to a valid set of publish targets.
28
+ *
29
+ * @since 0.1.0
30
+ */
31
+ export declare class PublishConfigError extends PublishConfigError_base<{
32
+ readonly packageName: string;
33
+ readonly reason: string;
34
+ }> {
35
+ get message(): string;
36
+ }
37
+
38
+ declare const PublishConfigError_base: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
39
+ readonly _tag: "PublishConfigError";
40
+ } & Readonly<A>;
41
+
42
+ /**
43
+ * The publish protocol used when pushing a package to a registry.
44
+ *
45
+ * @remarks
46
+ * `"npm"` covers all npm-compatible registries (npmjs.org, GitHub Packages, custom).
47
+ * `"jsr"` targets the JSR registry via its own publish tool.
48
+ *
49
+ * @since 0.1.0
50
+ */
51
+ export declare const PublishProtocol: Schema.Literal<["npm", "jsr"]>;
52
+
53
+ /** @since 0.1.0 */
54
+ export declare type PublishProtocol = typeof PublishProtocol.Type;
55
+
56
+ /**
57
+ * Union of all accepted publish-target representations.
58
+ *
59
+ * @remarks
60
+ * Accepts a {@link PublishTargetShorthand} string (`"npm"`, `"github"`, `"jsr"`),
61
+ * an `https://` URL pointing to a custom npm-compatible registry, or a full
62
+ * {@link PublishTargetObject} with explicit field overrides.
63
+ *
64
+ * @since 0.1.0
65
+ */
66
+ export declare const PublishTarget: Schema.Union<[Schema.Literal<["npm", "github", "jsr"]>, Schema.filter<typeof Schema.String>, Schema.Struct<{
67
+ protocol: Schema.optionalWith<Schema.Literal<["npm", "jsr"]>, {
68
+ default: () => "npm";
69
+ }>;
70
+ registry: Schema.optional<typeof Schema.String>;
71
+ directory: Schema.optional<typeof Schema.String>;
72
+ access: Schema.optional<Schema.Literal<["public", "restricted"]>>;
73
+ provenance: Schema.optional<typeof Schema.Boolean>;
74
+ tag: Schema.optional<typeof Schema.String>;
75
+ }>]>;
76
+
77
+ /** @since 0.1.0 */
78
+ export declare type PublishTarget = typeof PublishTarget.Type;
79
+
80
+ /**
81
+ * Full publish-target configuration expressed as a structured object.
82
+ *
83
+ * @remarks
84
+ * All fields are optional and fall back to sensible defaults when omitted.
85
+ * `protocol` defaults to `"npm"`. `access` defaults to the registry default.
86
+ *
87
+ * @since 0.1.0
88
+ */
89
+ export declare const PublishTargetObject: Schema.Struct<{
90
+ protocol: Schema.optionalWith<Schema.Literal<["npm", "jsr"]>, {
91
+ default: () => "npm";
92
+ }>;
93
+ registry: Schema.optional<typeof Schema.String>;
94
+ directory: Schema.optional<typeof Schema.String>;
95
+ access: Schema.optional<Schema.Literal<["public", "restricted"]>>;
96
+ provenance: Schema.optional<typeof Schema.Boolean>;
97
+ tag: Schema.optional<typeof Schema.String>;
98
+ }>;
99
+
100
+ /** @since 0.1.0 */
101
+ export declare type PublishTargetObject = typeof PublishTargetObject.Type;
102
+
103
+ /**
104
+ * Shorthand string identifiers for common publish destinations.
105
+ *
106
+ * @remarks
107
+ * - `"npm"` — the public npm registry, authenticated via OIDC.
108
+ * - `"github"` — GitHub Packages, authenticated via `GITHUB_TOKEN`.
109
+ * - `"jsr"` — the JSR registry, authenticated via OIDC.
110
+ *
111
+ * @since 0.1.0
112
+ */
113
+ export declare const PublishTargetShorthand: Schema.Literal<["npm", "github", "jsr"]>;
114
+
115
+ /** @since 0.1.0 */
116
+ export declare type PublishTargetShorthand = typeof PublishTargetShorthand.Type;
117
+
118
+ /**
119
+ * Fully resolved publish target with all fields populated and defaults applied.
120
+ *
121
+ * @remarks
122
+ * Produced by {@link TargetResolver.resolve} from any {@link PublishTarget} input.
123
+ * All optional fields from {@link PublishTargetObject} become required here,
124
+ * and `auth` / `tokenEnv` are derived from the registry URL.
125
+ *
126
+ * @since 0.1.0
127
+ */
128
+ export declare const ResolvedTarget: Schema.Struct<{
129
+ protocol: Schema.Literal<["npm", "jsr"]>;
130
+ registry: Schema.NullOr<typeof Schema.String>;
131
+ directory: typeof Schema.String;
132
+ access: Schema.Literal<["public", "restricted"]>;
133
+ provenance: typeof Schema.Boolean;
134
+ tag: typeof Schema.String;
135
+ auth: Schema.Literal<["oidc", "token"]>;
136
+ tokenEnv: Schema.NullOr<typeof Schema.String>;
137
+ }>;
138
+
139
+ /** @since 0.1.0 */
140
+ export declare type ResolvedTarget = typeof ResolvedTarget.Type;
141
+
142
+ /**
143
+ * Service that determines whether a package is publishable and resolves its targets.
144
+ *
145
+ * @remarks
146
+ * Inspects the `package.json` object using the Silk publishability rules:
147
+ * - `private: true` with no `publishConfig` → not publishable (empty array).
148
+ * - `publishConfig` without `access` or `targets` → not publishable.
149
+ * - `publishConfig.targets` (array) → resolved via {@link TargetResolver}.
150
+ * - `publishConfig.registry` → resolved as a single registry target.
151
+ * - Default → resolved as `"npm"`.
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * const result = await Effect.runPromise(
156
+ * Effect.gen(function* () {
157
+ * const plugin = yield* SilkPublishabilityPlugin;
158
+ * return yield* plugin.detect({ publishConfig: { access: "public" } });
159
+ * }).pipe(
160
+ * Effect.provide(SilkPublishabilityPluginLive),
161
+ * Effect.provide(TargetResolverLive),
162
+ * )
163
+ * );
164
+ * ```
165
+ *
166
+ * @since 0.1.0
167
+ */
168
+ export declare class SilkPublishabilityPlugin extends SilkPublishabilityPlugin_base {
169
+ }
170
+
171
+ declare const SilkPublishabilityPlugin_base: Context.TagClass<SilkPublishabilityPlugin, "@savvy-web/silk-effects/SilkPublishabilityPlugin", {
172
+ /**
173
+ * Inspect a parsed `package.json` object and return the resolved publish targets.
174
+ *
175
+ * @param pkgJson - The parsed `package.json` contents.
176
+ * @returns An `Effect` that succeeds with an array of {@link ResolvedTarget} records
177
+ * (empty when the package is not publishable), or fails with {@link TargetResolutionError}.
178
+ *
179
+ * @since 0.1.0
180
+ */
181
+ readonly detect: (pkgJson: Record<string, unknown>) => Effect.Effect<ReadonlyArray<ResolvedTarget>, TargetResolutionError>;
182
+ }>;
183
+
184
+ /**
185
+ * Live implementation of {@link SilkPublishabilityPlugin}.
186
+ *
187
+ * @remarks
188
+ * Requires {@link TargetResolver} to resolve target strings and objects.
189
+ *
190
+ * @since 0.1.0
191
+ */
192
+ export declare const SilkPublishabilityPluginLive: Layer.Layer<SilkPublishabilityPlugin, never, TargetResolver>;
193
+
194
+ /**
195
+ * Raised when a publish target value cannot be resolved into a {@link ResolvedTarget}.
196
+ *
197
+ * @remarks
198
+ * Returned by {@link TargetResolver.resolve} when the input is not a recognised shorthand,
199
+ * a valid `https://` URL, or a well-formed object target.
200
+ *
201
+ * @since 0.1.0
202
+ */
203
+ export declare class TargetResolutionError extends TargetResolutionError_base<{
204
+ readonly target: unknown;
205
+ readonly reason: string;
206
+ }> {
207
+ get message(): string;
208
+ }
209
+
210
+ declare const TargetResolutionError_base: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
211
+ readonly _tag: "TargetResolutionError";
212
+ } & Readonly<A>;
213
+
214
+ /**
215
+ * Service that resolves raw publish-target values into fully-normalised {@link ResolvedTarget} records.
216
+ *
217
+ * @remarks
218
+ * Accepts a single target or an array of targets. Each item may be a
219
+ * {@link PublishTargetShorthand} string, an `https://` registry URL, or a
220
+ * {@link PublishTargetObject}. Unknown values produce a {@link TargetResolutionError}.
221
+ *
222
+ * @example
223
+ * ```typescript
224
+ * const result = await Effect.runPromise(
225
+ * Effect.gen(function* () {
226
+ * const resolver = yield* TargetResolver;
227
+ * return yield* resolver.resolve("npm");
228
+ * }).pipe(Effect.provide(TargetResolverLive))
229
+ * );
230
+ * ```
231
+ *
232
+ * @since 0.1.0
233
+ */
234
+ export declare class TargetResolver extends TargetResolver_base {
235
+ }
236
+
237
+ declare const TargetResolver_base: Context.TagClass<TargetResolver, "@savvy-web/silk-effects/TargetResolver", {
238
+ /**
239
+ * Resolve one target (or an array of targets) into an array of {@link ResolvedTarget} records.
240
+ *
241
+ * @param target - A single publish-target value or an array of them.
242
+ * @returns An `Effect` that succeeds with the resolved targets or fails with {@link TargetResolutionError}.
243
+ *
244
+ * @since 0.1.0
245
+ */
246
+ readonly resolve: (target: unknown) => Effect.Effect<ReadonlyArray<ResolvedTarget>, TargetResolutionError>;
247
+ }>;
248
+
249
+ /**
250
+ * Live implementation of {@link TargetResolver} with no external dependencies.
251
+ *
252
+ * @remarks
253
+ * All resolution logic is pure: shorthand strings, `https://` URLs, and object targets
254
+ * are mapped to {@link ResolvedTarget} records without any I/O.
255
+ *
256
+ * @since 0.1.0
257
+ */
258
+ export declare const TargetResolverLive: Layer.Layer<TargetResolver, never, never>;
259
+
260
+ export { }
package/publish.js ADDED
@@ -0,0 +1,124 @@
1
+ import { Context, Data, Effect, Layer } from "effect";
2
+ class TargetResolutionError extends Data.TaggedError("TargetResolutionError") {
3
+ get message() {
4
+ return `Failed to resolve publish target: ${this.reason}`;
5
+ }
6
+ }
7
+ class PublishConfigError extends Data.TaggedError("PublishConfigError") {
8
+ get message() {
9
+ return `Invalid publishConfig for ${this.packageName}: ${this.reason}`;
10
+ }
11
+ }
12
+ class TargetResolver extends Context.Tag("@savvy-web/silk-effects/TargetResolver")() {
13
+ }
14
+ const DEFAULTS = {
15
+ directory: "dist/npm",
16
+ access: "public",
17
+ provenance: false,
18
+ tag: "latest"
19
+ };
20
+ function deriveTokenEnv(registryUrl) {
21
+ try {
22
+ const hostname = new URL(registryUrl).hostname;
23
+ return `NPM_TOKEN_${hostname.replace(/\./g, "_").toUpperCase()}`;
24
+ } catch {
25
+ return "NPM_TOKEN";
26
+ }
27
+ }
28
+ function resolveOne(target) {
29
+ if ("npm" === target) return Effect.succeed({
30
+ ...DEFAULTS,
31
+ protocol: "npm",
32
+ registry: "https://registry.npmjs.org/",
33
+ auth: "oidc",
34
+ tokenEnv: null
35
+ });
36
+ if ("github" === target) return Effect.succeed({
37
+ ...DEFAULTS,
38
+ protocol: "npm",
39
+ registry: "https://npm.pkg.github.com/",
40
+ auth: "token",
41
+ tokenEnv: "GITHUB_TOKEN"
42
+ });
43
+ if ("jsr" === target) return Effect.succeed({
44
+ ...DEFAULTS,
45
+ protocol: "jsr",
46
+ registry: null,
47
+ auth: "oidc",
48
+ tokenEnv: null
49
+ });
50
+ if ("string" == typeof target && target.startsWith("https://")) return Effect.succeed({
51
+ ...DEFAULTS,
52
+ protocol: "npm",
53
+ registry: target,
54
+ auth: "token",
55
+ tokenEnv: deriveTokenEnv(target)
56
+ });
57
+ if ("object" == typeof target && null !== target && !Array.isArray(target)) {
58
+ const obj = target;
59
+ const protocol = obj.protocol ?? "npm";
60
+ const registry = obj.registry ?? null;
61
+ const directory = obj.directory ?? DEFAULTS.directory;
62
+ const access = obj.access ?? DEFAULTS.access;
63
+ const provenance = obj.provenance ?? DEFAULTS.provenance;
64
+ const tag = obj.tag ?? DEFAULTS.tag;
65
+ let auth;
66
+ let tokenEnv;
67
+ if (null !== registry) try {
68
+ const hostname = new URL(registry).hostname;
69
+ if ("npm.pkg.github.com" === hostname) {
70
+ auth = "token";
71
+ tokenEnv = "GITHUB_TOKEN";
72
+ } else {
73
+ auth = "oidc";
74
+ tokenEnv = null;
75
+ }
76
+ } catch {
77
+ auth = "oidc";
78
+ tokenEnv = null;
79
+ }
80
+ else {
81
+ auth = "oidc";
82
+ tokenEnv = null;
83
+ }
84
+ return Effect.succeed({
85
+ protocol,
86
+ registry,
87
+ directory,
88
+ access,
89
+ provenance,
90
+ tag,
91
+ auth,
92
+ tokenEnv
93
+ });
94
+ }
95
+ return Effect.fail(new TargetResolutionError({
96
+ target,
97
+ reason: `Unsupported target type: ${typeof target}. Expected "npm", "github", "jsr", an https:// URL, or an object.`
98
+ }));
99
+ }
100
+ const TargetResolverLive = Layer.succeed(TargetResolver, {
101
+ resolve: (target)=>{
102
+ if (Array.isArray(target)) return Effect.all(target.map(resolveOne));
103
+ return resolveOne(target).pipe(Effect.map((resolved)=>[
104
+ resolved
105
+ ]));
106
+ }
107
+ });
108
+ class SilkPublishabilityPlugin extends Context.Tag("@savvy-web/silk-effects/SilkPublishabilityPlugin")() {
109
+ }
110
+ const SilkPublishabilityPluginLive = Layer.effect(SilkPublishabilityPlugin, Effect.gen(function*() {
111
+ const resolver = yield* TargetResolver;
112
+ return {
113
+ detect: (pkgJson)=>{
114
+ const isPrivate = true === pkgJson.private;
115
+ const publishConfig = pkgJson.publishConfig;
116
+ if (isPrivate && !publishConfig) return Effect.succeed([]);
117
+ if (!publishConfig || !publishConfig.access && !publishConfig.targets) return Effect.succeed([]);
118
+ if (Array.isArray(publishConfig.targets)) return resolver.resolve(publishConfig.targets);
119
+ if (publishConfig.registry) return resolver.resolve(publishConfig.registry);
120
+ return resolver.resolve("npm");
121
+ }
122
+ };
123
+ }));
124
+ export { PublishConfigError, SilkPublishabilityPlugin, SilkPublishabilityPluginLive, TargetResolutionError, TargetResolver, TargetResolverLive };
package/tags.d.ts ADDED
@@ -0,0 +1,122 @@
1
+ import { Context } from 'effect';
2
+ import { Effect } from 'effect';
3
+ import { Layer } from 'effect';
4
+ import { Schema } from 'effect';
5
+ import { VoidIfEmpty } from 'effect/Types';
6
+ import { YieldableError } from 'effect/Cause';
7
+
8
+ /**
9
+ * Raised when a git tag string cannot be formatted for the given package name and version.
10
+ *
11
+ * @remarks
12
+ * Returned by {@link TagStrategy.formatTag} when the `version` argument is an empty string
13
+ * or another invariant prevents tag construction.
14
+ *
15
+ * @since 0.1.0
16
+ */
17
+ export declare class TagFormatError extends TagFormatError_base<{
18
+ readonly name: string;
19
+ readonly version: string;
20
+ readonly reason: string;
21
+ }> {
22
+ get message(): string;
23
+ }
24
+
25
+ declare const TagFormatError_base: new <A extends Record<string, any> = {}>(args: VoidIfEmpty< { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
26
+ readonly _tag: "TagFormatError";
27
+ } & Readonly<A>;
28
+
29
+ /**
30
+ * Service that determines and applies the git-tag naming strategy for a release.
31
+ *
32
+ * @remarks
33
+ * Consumes a {@link VersioningStrategyResult} to pick between `"single"` and `"scoped"`
34
+ * tag formats, then formats tag strings accordingly. Independent versioning always
35
+ * produces scoped tags; single and fixed-group versioning produces a single shared tag.
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const result = await Effect.runPromise(
40
+ * Effect.gen(function* () {
41
+ * const tags = yield* TagStrategy;
42
+ * const strategyType = yield* tags.determine({ type: "independent", fixedGroups: [], publishablePackages: [] });
43
+ * return yield* tags.formatTag("@my-org/pkg", "1.2.3", strategyType);
44
+ * }).pipe(Effect.provide(TagStrategyLive))
45
+ * );
46
+ * // => "@my-org/pkg@1.2.3"
47
+ * ```
48
+ *
49
+ * @since 0.1.0
50
+ */
51
+ export declare class TagStrategy extends TagStrategy_base {
52
+ }
53
+
54
+ declare const TagStrategy_base: Context.TagClass<TagStrategy, "@savvy-web/silk-effects/TagStrategy", {
55
+ /**
56
+ * Determine the appropriate tag strategy type from a versioning strategy result.
57
+ *
58
+ * @param versioningResult - The result of {@link VersioningStrategy.detect}.
59
+ * @returns An `Effect` that always succeeds with a {@link TagStrategyType}.
60
+ *
61
+ * @since 0.1.0
62
+ */
63
+ readonly determine: (versioningResult: VersioningStrategyResult) => Effect.Effect<TagStrategyType>;
64
+ /**
65
+ * Format a git tag string for a given package name, version, and strategy.
66
+ *
67
+ * @param name - The package name (e.g. `"@my-org/pkg"` or `"my-pkg"`).
68
+ * @param version - The semver version string (e.g. `"1.2.3"`). Must not be empty.
69
+ * @param strategy - The {@link TagStrategyType} to apply.
70
+ * @returns An `Effect` that resolves to the formatted tag string, or fails with
71
+ * {@link TagFormatError} when `version` is empty.
72
+ *
73
+ * @since 0.1.0
74
+ */
75
+ readonly formatTag: (name: string, version: string, strategy: TagStrategyType) => Effect.Effect<string, TagFormatError>;
76
+ }>;
77
+
78
+ /**
79
+ * Live implementation of {@link TagStrategy} with no external dependencies.
80
+ *
81
+ * @remarks
82
+ * All logic is pure: strategy determination and tag formatting involve no I/O.
83
+ *
84
+ * @since 0.1.0
85
+ */
86
+ export declare const TagStrategyLive: Layer.Layer<TagStrategy>;
87
+
88
+ /**
89
+ * Git tag naming strategy for a workspace.
90
+ *
91
+ * @remarks
92
+ * - `"single"` — one shared tag for the entire release (e.g. `1.2.3`).
93
+ * - `"scoped"` — a per-package tag that includes the package name (e.g. `@my-org/pkg@1.2.3`).
94
+ *
95
+ * Determined by {@link TagStrategy.determine} based on the {@link VersioningStrategyResult}.
96
+ *
97
+ * @since 0.1.0
98
+ */
99
+ export declare const TagStrategyType: Schema.Literal<["single", "scoped"]>;
100
+
101
+ /** @since 0.1.0 */
102
+ export declare type TagStrategyType = typeof TagStrategyType.Type;
103
+
104
+ /**
105
+ * Output of the versioning strategy detection, combining the strategy type with group metadata.
106
+ *
107
+ * @remarks
108
+ * Produced by {@link VersioningStrategy.detect} and consumed by {@link TagStrategy.determine}
109
+ * to decide on the appropriate git-tag format.
110
+ *
111
+ * @since 0.1.0
112
+ */
113
+ declare const VersioningStrategyResult: Schema.Struct<{
114
+ type: Schema.Literal<["single", "fixed-group", "independent"]>;
115
+ fixedGroups: Schema.Array$<Schema.Array$<typeof Schema.String>>;
116
+ publishablePackages: Schema.Array$<typeof Schema.String>;
117
+ }>;
118
+
119
+ /** @since 0.1.0 */
120
+ declare type VersioningStrategyResult = typeof VersioningStrategyResult.Type;
121
+
122
+ export { }
package/tags.js ADDED
@@ -0,0 +1,25 @@
1
+ import { Context, Data, Effect, Layer } from "effect";
2
+ class TagFormatError extends Data.TaggedError("TagFormatError") {
3
+ get message() {
4
+ return `Failed to format tag for ${this.name}@${this.version}: ${this.reason}`;
5
+ }
6
+ }
7
+ class TagStrategy extends Context.Tag("@savvy-web/silk-effects/TagStrategy")() {
8
+ }
9
+ const TagStrategyLive = Layer.succeed(TagStrategy, TagStrategy.of({
10
+ determine: (versioningResult)=>{
11
+ if ("independent" === versioningResult.type) return Effect.succeed("scoped");
12
+ return Effect.succeed("single");
13
+ },
14
+ formatTag: (name, version, strategy)=>{
15
+ if ("" === version) return Effect.fail(new TagFormatError({
16
+ name,
17
+ version,
18
+ reason: "version cannot be empty"
19
+ }));
20
+ if ("single" === strategy) return Effect.succeed(version);
21
+ name.startsWith("@");
22
+ return Effect.succeed(`${name}@${version}`);
23
+ }
24
+ }));
25
+ export { TagFormatError, TagStrategy, TagStrategyLive };
@@ -0,0 +1,11 @@
1
+ // This file is read by tools that parse documentation comments conforming to the TSDoc standard.
2
+ // It should be published with your NPM package. It should not be tracked by Git.
3
+ {
4
+ "tsdocVersion": "0.12",
5
+ "toolPackages": [
6
+ {
7
+ "packageName": "@microsoft/api-extractor",
8
+ "packageVersion": "7.57.7"
9
+ }
10
+ ]
11
+ }