@savvy-web/silk-core 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/LICENSE +21 -0
- package/README.md +47 -0
- package/_virtual/_rolldown/runtime.js +18 -0
- package/errors/BiomeSyncError.js +22 -0
- package/errors/ChangesetConfigError.js +21 -0
- package/errors/ConfigNotFoundError.js +22 -0
- package/errors/PublishTargetBindingError.js +30 -0
- package/errors/WorkspaceAnalysisError.js +22 -0
- package/index.d.ts +1261 -0
- package/index.js +15 -0
- package/package.json +39 -0
- package/pr-body/body.js +145 -0
- package/pr-body/diagnostics.js +104 -0
- package/pr-body/index.js +22 -0
- package/pr-body/linked-issue.js +44 -0
- package/pr-body/markers.js +103 -0
- package/pr-body/references.js +157 -0
- package/pr-body/region.js +105 -0
- package/schemas/BiomeConfig.js +36 -0
- package/schemas/ConfigDiscoverySchemas.js +50 -0
- package/schemas/SavvyInstallSection.js +232 -0
- package/schemas/SavvySections.js +194 -0
- package/schemas/VersioningSchemas.js +87 -0
- package/schemas/WorkspaceAnalysisSchemas.js +209 -0
- package/tsdoc-metadata.json +11 -0
- package/utils/TrailingSlash.js +21 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/schemas/VersioningSchemas.ts
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for how private packages are handled during versioning.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* When set to `false`, private packages are completely ignored.
|
|
9
|
+
* When set to an object, `tag` and `version` control whether private packages
|
|
10
|
+
* receive git tags and version bumps respectively.
|
|
11
|
+
*
|
|
12
|
+
* @since 0.2.0
|
|
13
|
+
*/
|
|
14
|
+
const PrivatePackagesConfig = Schema.Union([Schema.Struct({
|
|
15
|
+
tag: Schema.optional(Schema.Boolean),
|
|
16
|
+
version: Schema.optional(Schema.Boolean)
|
|
17
|
+
}), Schema.Literal(false)]);
|
|
18
|
+
/**
|
|
19
|
+
* Snapshot release configuration for changesets.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* Controls how snapshot versions are generated.
|
|
23
|
+
* `useCalculatedVersion` prepends the calculated version to the snapshot tag.
|
|
24
|
+
* `prereleaseTemplate` is a custom template string for snapshot version format.
|
|
25
|
+
*
|
|
26
|
+
* @since 0.2.0
|
|
27
|
+
*/
|
|
28
|
+
const SnapshotConfig = Schema.Struct({
|
|
29
|
+
useCalculatedVersion: Schema.optional(Schema.Boolean),
|
|
30
|
+
prereleaseTemplate: Schema.optional(Schema.String)
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Standard changesets configuration matching the `@changesets/config@4.0.0` spec.
|
|
34
|
+
*
|
|
35
|
+
* @remarks
|
|
36
|
+
* Represents the parsed `.changeset/config.json` file. All fields are optional
|
|
37
|
+
* to allow partial configs. Use {@link (SilkChangesetConfigFile:type)} when the Silk changelog
|
|
38
|
+
* adapter is detected.
|
|
39
|
+
*
|
|
40
|
+
* @since 0.1.0
|
|
41
|
+
*/
|
|
42
|
+
/** @public */
|
|
43
|
+
const ChangesetConfigFile = Schema.Struct({
|
|
44
|
+
changelog: Schema.optional(Schema.Union([
|
|
45
|
+
Schema.String,
|
|
46
|
+
Schema.Array(Schema.Unknown),
|
|
47
|
+
Schema.Literal(false)
|
|
48
|
+
])),
|
|
49
|
+
commit: Schema.optional(Schema.Union([
|
|
50
|
+
Schema.Boolean,
|
|
51
|
+
Schema.String,
|
|
52
|
+
Schema.Array(Schema.Unknown)
|
|
53
|
+
])),
|
|
54
|
+
fixed: Schema.optional(Schema.Array(Schema.Array(Schema.String))),
|
|
55
|
+
linked: Schema.optional(Schema.Array(Schema.Array(Schema.String))),
|
|
56
|
+
access: Schema.optional(Schema.Literals(["public", "restricted"])),
|
|
57
|
+
baseBranch: Schema.optional(Schema.String),
|
|
58
|
+
updateInternalDependencies: Schema.optional(Schema.Literals([
|
|
59
|
+
"patch",
|
|
60
|
+
"minor",
|
|
61
|
+
"major"
|
|
62
|
+
])),
|
|
63
|
+
ignore: Schema.optional(Schema.Array(Schema.String)),
|
|
64
|
+
privatePackages: Schema.optional(PrivatePackagesConfig),
|
|
65
|
+
prettier: Schema.optional(Schema.Boolean),
|
|
66
|
+
changedFilePatterns: Schema.optional(Schema.Array(Schema.String)),
|
|
67
|
+
bumpVersionsWithWorkspaceProtocolOnly: Schema.optional(Schema.Boolean),
|
|
68
|
+
snapshot: Schema.optional(SnapshotConfig)
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* Extended changeset config for repos using the `@savvy-web/changesets` changelog adapter.
|
|
72
|
+
*
|
|
73
|
+
* @remarks
|
|
74
|
+
* Extends {@link (ChangesetConfigFile:type)} with a `_isSilk` marker flag that is automatically
|
|
75
|
+
* set to `true`. Detected by `ChangesetConfigReader` when the `changelog` field
|
|
76
|
+
* references `@savvy-web/changesets`.
|
|
77
|
+
*
|
|
78
|
+
* @since 0.1.0
|
|
79
|
+
*/
|
|
80
|
+
/** @public */
|
|
81
|
+
const SilkChangesetConfigFile = Schema.Struct({
|
|
82
|
+
...ChangesetConfigFile.fields,
|
|
83
|
+
_isSilk: Schema.Boolean.pipe(Schema.withDecodingDefaultType(Effect.succeed(true)), Schema.withConstructorDefault(Effect.succeed(true)))
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
87
|
+
export { ChangesetConfigFile, SilkChangesetConfigFile };
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { ChangesetConfigFile, SilkChangesetConfigFile } from "./VersioningSchemas.js";
|
|
2
|
+
import { trimTrailingSlashes } from "../utils/TrailingSlash.js";
|
|
3
|
+
import { Effect, Equal, Function, Hash, Option, Schema } from "effect";
|
|
4
|
+
import { PublishConfig, PublishTarget, TagStyle, VersioningStrategy } from "@effected/workspaces";
|
|
5
|
+
|
|
6
|
+
//#region src/schemas/WorkspaceAnalysisSchemas.ts
|
|
7
|
+
const PublishProtocol = Schema.Literals(["npm", "jsr"]);
|
|
8
|
+
const PublishTargetShorthand = Schema.Literals([
|
|
9
|
+
"npm",
|
|
10
|
+
"github",
|
|
11
|
+
"jsr"
|
|
12
|
+
]);
|
|
13
|
+
const PublishTargetObject = Schema.Struct({
|
|
14
|
+
protocol: PublishProtocol.pipe(Schema.withDecodingDefaultType(Effect.succeed("npm")), Schema.withConstructorDefault(Effect.succeed("npm"))),
|
|
15
|
+
registry: Schema.optional(Schema.String),
|
|
16
|
+
directory: Schema.optional(Schema.String),
|
|
17
|
+
access: Schema.optional(Schema.Literals(["public", "restricted"])),
|
|
18
|
+
provenance: Schema.optional(Schema.Boolean),
|
|
19
|
+
tag: Schema.optional(Schema.String)
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Silk-extended publishConfig schema.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* Extends the base PublishConfig from `@effected/workspaces` (which covers the
|
|
26
|
+
* npm standard fields — access, registry, directory, tag — and, as of kit
|
|
27
|
+
* round 3, `linkDirectory`) with the Silk `targets` extension for
|
|
28
|
+
* multi-registry publishing.
|
|
29
|
+
*
|
|
30
|
+
* @since 0.2.0
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
var SilkPublishConfig = class extends PublishConfig.extend("SilkPublishConfig")({ targets: Schema.optional(Schema.Array(Schema.Union([PublishTargetShorthand, PublishTargetObject]))) }) {};
|
|
34
|
+
const KNOWN_REGISTRIES = {
|
|
35
|
+
npm: "https://registry.npmjs.org/",
|
|
36
|
+
github: "https://npm.pkg.github.com/",
|
|
37
|
+
jsr: "https://jsr.io/"
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Compare registry URLs ignoring a trailing slash. `SilkPublishability` resolves
|
|
41
|
+
* targets from the bundler's `dist/prod/targets.json` binding, which writes
|
|
42
|
+
* registry endpoints WITHOUT a trailing slash (`https://registry.npmjs.org`),
|
|
43
|
+
* while `KNOWN_REGISTRIES` / `NPM_DEFAULT` use the trailing-slash form. Normalize
|
|
44
|
+
* both sides so `hasTarget`/`targetFor` match regardless of which form a target
|
|
45
|
+
* carries (binding-driven, placeholder, or access-branch fallback).
|
|
46
|
+
*/
|
|
47
|
+
const sameRegistry = (a, b) => trimTrailingSlashes(a) === trimTrailingSlashes(b);
|
|
48
|
+
/**
|
|
49
|
+
* The package's declared version. `current` is absent for a member whose manifest carries no
|
|
50
|
+
* `version` — legal for a private package and the ordinary shape for a private monorepo root,
|
|
51
|
+
* which `@effected/workspaces` discovers as a member rather than rejecting (its `missingVersion`
|
|
52
|
+
* failure kind was retired in 0.19.0). Such a package has no version to bump, tag or stamp.
|
|
53
|
+
*/
|
|
54
|
+
const WorkspaceVersion = Schema.Struct({ current: Schema.optional(Schema.String) });
|
|
55
|
+
/**
|
|
56
|
+
* A fully analyzed workspace with publish targets, versioning status,
|
|
57
|
+
* and release group membership.
|
|
58
|
+
*
|
|
59
|
+
* @since 0.2.0
|
|
60
|
+
* @public
|
|
61
|
+
*/
|
|
62
|
+
var AnalyzedWorkspace = class AnalyzedWorkspace extends Schema.TaggedClass()("AnalyzedWorkspace", {
|
|
63
|
+
name: Schema.String,
|
|
64
|
+
version: WorkspaceVersion,
|
|
65
|
+
path: Schema.String,
|
|
66
|
+
root: Schema.Boolean,
|
|
67
|
+
publishConfig: Schema.NullOr(SilkPublishConfig),
|
|
68
|
+
publishable: Schema.Boolean,
|
|
69
|
+
targets: Schema.Array(PublishTarget),
|
|
70
|
+
versioned: Schema.Boolean,
|
|
71
|
+
tagged: Schema.Boolean,
|
|
72
|
+
released: Schema.Boolean,
|
|
73
|
+
linked: Schema.Array(Schema.suspend(() => AnalyzedWorkspace)),
|
|
74
|
+
fixed: Schema.Array(Schema.suspend(() => AnalyzedWorkspace))
|
|
75
|
+
}) {
|
|
76
|
+
get isRoot() {
|
|
77
|
+
return this.root;
|
|
78
|
+
}
|
|
79
|
+
get isPublishable() {
|
|
80
|
+
return this.publishable;
|
|
81
|
+
}
|
|
82
|
+
get isReleasable() {
|
|
83
|
+
return this.released;
|
|
84
|
+
}
|
|
85
|
+
get isFixed() {
|
|
86
|
+
return this.fixed.length > 0;
|
|
87
|
+
}
|
|
88
|
+
get isLinked() {
|
|
89
|
+
return this.linked.length > 0;
|
|
90
|
+
}
|
|
91
|
+
publishesTo(registry) {
|
|
92
|
+
return this.targets.some((t) => sameRegistry(t.registry, registry));
|
|
93
|
+
}
|
|
94
|
+
hasTarget(shorthand) {
|
|
95
|
+
const registry = KNOWN_REGISTRIES[shorthand];
|
|
96
|
+
return registry !== void 0 && this.publishesTo(registry);
|
|
97
|
+
}
|
|
98
|
+
targetFor(registry) {
|
|
99
|
+
const found = this.targets.find((t) => sameRegistry(t.registry, registry));
|
|
100
|
+
return found ? Option.some(found) : Option.none();
|
|
101
|
+
}
|
|
102
|
+
[Equal.symbol](that) {
|
|
103
|
+
if (!(that instanceof AnalyzedWorkspace)) return false;
|
|
104
|
+
return this.name === that.name && this.path === that.path;
|
|
105
|
+
}
|
|
106
|
+
[Hash.symbol]() {
|
|
107
|
+
return Hash.optimize(Hash.combine(Hash.hash(this.name), Hash.hash(this.path)));
|
|
108
|
+
}
|
|
109
|
+
toString() {
|
|
110
|
+
return this.version.current === void 0 ? this.name : `${this.name}@${this.version.current}`;
|
|
111
|
+
}
|
|
112
|
+
toJSON() {
|
|
113
|
+
return {
|
|
114
|
+
_tag: "AnalyzedWorkspace",
|
|
115
|
+
name: this.name,
|
|
116
|
+
version: this.version,
|
|
117
|
+
path: this.path,
|
|
118
|
+
root: this.root,
|
|
119
|
+
publishable: this.publishable,
|
|
120
|
+
targets: this.targets,
|
|
121
|
+
versioned: this.versioned,
|
|
122
|
+
tagged: this.tagged,
|
|
123
|
+
released: this.released
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
static publishable(workspaces) {
|
|
127
|
+
return workspaces.filter((w) => w.publishable);
|
|
128
|
+
}
|
|
129
|
+
static releasable(workspaces) {
|
|
130
|
+
return workspaces.filter((w) => w.released);
|
|
131
|
+
}
|
|
132
|
+
static findByName;
|
|
133
|
+
/** Pretty-print an AnalyzedWorkspace instance. */
|
|
134
|
+
static pretty;
|
|
135
|
+
};
|
|
136
|
+
AnalyzedWorkspace.findByName = Function.dual(2, (workspaces, name) => {
|
|
137
|
+
const found = workspaces.find((w) => w.name === name);
|
|
138
|
+
return found ? Option.some(found) : Option.none();
|
|
139
|
+
});
|
|
140
|
+
AnalyzedWorkspace.pretty = Schema.toFormatter(AnalyzedWorkspace);
|
|
141
|
+
const PackageManagerInfo = Schema.Struct({
|
|
142
|
+
type: Schema.Literals([
|
|
143
|
+
"npm",
|
|
144
|
+
"pnpm",
|
|
145
|
+
"yarn",
|
|
146
|
+
"bun"
|
|
147
|
+
]),
|
|
148
|
+
version: Schema.optional(Schema.String)
|
|
149
|
+
});
|
|
150
|
+
/**
|
|
151
|
+
* Full workspace analysis result containing all analyzed workspaces
|
|
152
|
+
* and project-level configuration.
|
|
153
|
+
*
|
|
154
|
+
* @since 0.2.0
|
|
155
|
+
* @public
|
|
156
|
+
*/
|
|
157
|
+
var WorkspaceAnalysis = class WorkspaceAnalysis extends Schema.TaggedClass()("WorkspaceAnalysis", {
|
|
158
|
+
root: Schema.String,
|
|
159
|
+
runtime: Schema.Literals(["node", "bun"]),
|
|
160
|
+
packageManager: PackageManagerInfo,
|
|
161
|
+
workspaces: Schema.Array(AnalyzedWorkspace),
|
|
162
|
+
changesetConfig: Schema.NullOr(Schema.Union([SilkChangesetConfigFile, ChangesetConfigFile])),
|
|
163
|
+
versioning: Schema.NullOr(VersioningStrategy),
|
|
164
|
+
tagStrategy: Schema.NullOr(TagStyle)
|
|
165
|
+
}) {
|
|
166
|
+
findWorkspace(name) {
|
|
167
|
+
const found = this.workspaces.find((w) => w.name === name);
|
|
168
|
+
return found ? Option.some(found) : Option.none();
|
|
169
|
+
}
|
|
170
|
+
get rootWorkspace() {
|
|
171
|
+
const root = this.workspaces.find((w) => w.root);
|
|
172
|
+
return root ? Option.some(root) : Option.none();
|
|
173
|
+
}
|
|
174
|
+
get publishableWorkspaces() {
|
|
175
|
+
return this.workspaces.filter((w) => w.publishable);
|
|
176
|
+
}
|
|
177
|
+
get versionedWorkspaces() {
|
|
178
|
+
return this.workspaces.filter((w) => w.versioned);
|
|
179
|
+
}
|
|
180
|
+
get taggedWorkspaces() {
|
|
181
|
+
return this.workspaces.filter((w) => w.tagged);
|
|
182
|
+
}
|
|
183
|
+
get releasableWorkspaces() {
|
|
184
|
+
return this.workspaces.filter((w) => w.released);
|
|
185
|
+
}
|
|
186
|
+
get isSilk() {
|
|
187
|
+
if (this.changesetConfig == null) return false;
|
|
188
|
+
return "_isSilk" in this.changesetConfig && this.changesetConfig._isSilk === true;
|
|
189
|
+
}
|
|
190
|
+
get hasChangesets() {
|
|
191
|
+
return this.changesetConfig != null;
|
|
192
|
+
}
|
|
193
|
+
[Equal.symbol](that) {
|
|
194
|
+
if (!(that instanceof WorkspaceAnalysis)) return false;
|
|
195
|
+
return this.root === that.root;
|
|
196
|
+
}
|
|
197
|
+
[Hash.symbol]() {
|
|
198
|
+
return Hash.optimize(Hash.hash(this.root));
|
|
199
|
+
}
|
|
200
|
+
toString() {
|
|
201
|
+
return `WorkspaceAnalysis(${this.root}, ${this.workspaces.length} workspaces)`;
|
|
202
|
+
}
|
|
203
|
+
/** Pretty-print a WorkspaceAnalysis instance. */
|
|
204
|
+
static pretty;
|
|
205
|
+
};
|
|
206
|
+
WorkspaceAnalysis.pretty = Schema.toFormatter(WorkspaceAnalysis);
|
|
207
|
+
|
|
208
|
+
//#endregion
|
|
209
|
+
export { AnalyzedWorkspace, SilkPublishConfig, WorkspaceAnalysis };
|
|
@@ -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.59.1"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/utils/TrailingSlash.ts
|
|
2
|
+
/**
|
|
3
|
+
* Trim trailing slashes from a string.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Trims trailing slashes with an index scan rather than `/\/+$/`. That regex is
|
|
7
|
+
* unanchored at the start, so the engine retries the match from every position
|
|
8
|
+
* and degrades to O(n²) on a string of many slashes (CodeQL `js/polynomial-redos`).
|
|
9
|
+
* Only a trailing run of slashes is removed; interior slash runs are untouched.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.1.0
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
const trimTrailingSlashes = (s) => {
|
|
15
|
+
let end = s.length;
|
|
16
|
+
while (end > 0 && s[end - 1] === "/") end -= 1;
|
|
17
|
+
return s.slice(0, end);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
export { trimTrailingSlashes };
|