@outfitter/tooling 0.3.0 → 0.3.3

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.
Files changed (54) hide show
  1. package/dist/cli/index.js +3 -6
  2. package/package.json +3 -2
  3. package/registry/registry.json +3 -3
  4. package/dist/cli/check-boundary-invocations.d.ts +0 -34
  5. package/dist/cli/check-boundary-invocations.js +0 -14
  6. package/dist/cli/check-bunup-registry.d.ts +0 -36
  7. package/dist/cli/check-bunup-registry.js +0 -12
  8. package/dist/cli/check-changeset.d.ts +0 -66
  9. package/dist/cli/check-changeset.js +0 -20
  10. package/dist/cli/check-clean-tree.d.ts +0 -36
  11. package/dist/cli/check-clean-tree.js +0 -14
  12. package/dist/cli/check-exports.d.ts +0 -2
  13. package/dist/cli/check-exports.js +0 -14
  14. package/dist/cli/check-readme-imports.d.ts +0 -61
  15. package/dist/cli/check-readme-imports.js +0 -198
  16. package/dist/cli/check-tsdoc.d.ts +0 -2
  17. package/dist/cli/check-tsdoc.js +0 -36
  18. package/dist/cli/check.d.ts +0 -19
  19. package/dist/cli/check.js +0 -10
  20. package/dist/cli/fix.d.ts +0 -19
  21. package/dist/cli/fix.js +0 -10
  22. package/dist/cli/init.d.ts +0 -31
  23. package/dist/cli/init.js +0 -12
  24. package/dist/cli/pre-push.d.ts +0 -48
  25. package/dist/cli/pre-push.js +0 -25
  26. package/dist/cli/upgrade-bun.d.ts +0 -8
  27. package/dist/cli/upgrade-bun.js +0 -8
  28. package/dist/registry/build.d.ts +0 -6
  29. package/dist/registry/build.js +0 -150
  30. package/dist/registry/index.d.ts +0 -3
  31. package/dist/registry/index.js +0 -13
  32. package/dist/registry/schema.d.ts +0 -2
  33. package/dist/registry/schema.js +0 -12
  34. package/dist/shared/@outfitter/tooling-0x5q15ec.js +0 -21
  35. package/dist/shared/@outfitter/tooling-1y8w5ahg.js +0 -70
  36. package/dist/shared/@outfitter/tooling-2n2dpsaa.js +0 -323
  37. package/dist/shared/@outfitter/tooling-9errkcvk.js +0 -21
  38. package/dist/shared/@outfitter/tooling-9vs606gq.d.ts +0 -3
  39. package/dist/shared/@outfitter/tooling-9yzd08v1.js +0 -146
  40. package/dist/shared/@outfitter/tooling-cj5vsa9k.js +0 -184
  41. package/dist/shared/@outfitter/tooling-ctmgnap5.js +0 -19
  42. package/dist/shared/@outfitter/tooling-dvwh9qve.js +0 -4
  43. package/dist/shared/@outfitter/tooling-enjcenja.js +0 -229
  44. package/dist/shared/@outfitter/tooling-kcvs6mys.js +0 -1
  45. package/dist/shared/@outfitter/tooling-mxwc1n8w.js +0 -68
  46. package/dist/shared/@outfitter/tooling-njw4z34x.d.ts +0 -140
  47. package/dist/shared/@outfitter/tooling-qk5xgmxr.js +0 -405
  48. package/dist/shared/@outfitter/tooling-r9976n43.js +0 -100
  49. package/dist/shared/@outfitter/tooling-sjm8nebx.d.ts +0 -109
  50. package/dist/shared/@outfitter/tooling-t17gnh9b.js +0 -78
  51. package/dist/shared/@outfitter/tooling-wesswf21.d.ts +0 -59
  52. package/dist/shared/@outfitter/tooling-wv09k6hr.js +0 -23
  53. package/dist/version.d.ts +0 -2
  54. package/dist/version.js +0 -8
@@ -1,323 +0,0 @@
1
- // @bun
2
- import {
3
- analyzeSourceFile,
4
- calculateCoverage
5
- } from "./tooling-qk5xgmxr.js";
6
-
7
- // packages/tooling/src/cli/pre-push.ts
8
- import { existsSync, readFileSync } from "fs";
9
- import { join, resolve } from "path";
10
- import ts from "typescript";
11
- var COLORS = {
12
- reset: "\x1B[0m",
13
- red: "\x1B[31m",
14
- green: "\x1B[32m",
15
- yellow: "\x1B[33m",
16
- blue: "\x1B[34m"
17
- };
18
- function log(msg) {
19
- process.stdout.write(`${msg}
20
- `);
21
- }
22
- function getCurrentBranch() {
23
- const result = Bun.spawnSync(["git", "rev-parse", "--abbrev-ref", "HEAD"]);
24
- return result.stdout.toString().trim();
25
- }
26
- function runGit(args) {
27
- try {
28
- const result = Bun.spawnSync(["git", ...args], { stderr: "ignore" });
29
- if (result.exitCode !== 0) {
30
- return { ok: false, lines: [] };
31
- }
32
- return {
33
- ok: true,
34
- lines: result.stdout.toString().split(`
35
- `).map((line) => line.trim()).filter(Boolean)
36
- };
37
- } catch {
38
- return { ok: false, lines: [] };
39
- }
40
- }
41
- function isRedPhaseBranch(branch) {
42
- return branch.endsWith("-tests") || branch.endsWith("/tests") || branch.endsWith("_tests");
43
- }
44
- function isScaffoldBranch(branch) {
45
- return branch.endsWith("-scaffold") || branch.endsWith("/scaffold") || branch.endsWith("_scaffold");
46
- }
47
- function isReleaseBranch(branch) {
48
- return branch.startsWith("changeset-release/");
49
- }
50
- var TEST_PATH_PATTERNS = [
51
- /(^|\/)__tests__\//,
52
- /(^|\/)__snapshots__\//,
53
- /\.(test|spec)\.[cm]?[jt]sx?$/,
54
- /\.snap$/,
55
- /(^|\/)(vitest|jest|bun)\.config\.[cm]?[jt]s$/,
56
- /(^|\/)tsconfig\.test\.json$/,
57
- /(^|\/)\.env\.test(\.|$)/
58
- ];
59
- function isTestOnlyPath(path) {
60
- const normalized = path.replaceAll("\\", "/");
61
- return TEST_PATH_PATTERNS.some((pattern) => pattern.test(normalized));
62
- }
63
- function areFilesTestOnly(paths) {
64
- return paths.length > 0 && paths.every((path) => isTestOnlyPath(path));
65
- }
66
- function canBypassRedPhaseByChangedFiles(changedFiles) {
67
- return changedFiles.deterministic && areFilesTestOnly(changedFiles.files);
68
- }
69
- function hasPackageSourceChanges(changedFiles) {
70
- const packageSrcPattern = /^packages\/[^/]+\/src\//;
71
- return changedFiles.files.some((f) => packageSrcPattern.test(f));
72
- }
73
- async function printTsdocSummary() {
74
- const glob = new Bun.Glob("packages/*/src/index.ts");
75
- const cwd = process.cwd();
76
- const allDeclarations = [];
77
- for (const entry of glob.scanSync({ cwd })) {
78
- const filePath = resolve(cwd, entry);
79
- const content = await Bun.file(filePath).text();
80
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
81
- allDeclarations.push(...analyzeSourceFile(sourceFile));
82
- }
83
- if (allDeclarations.length === 0)
84
- return;
85
- const coverage = calculateCoverage(allDeclarations);
86
- const parts = [];
87
- if (coverage.documented > 0)
88
- parts.push(`${coverage.documented} documented`);
89
- if (coverage.partial > 0)
90
- parts.push(`${coverage.partial} partial`);
91
- if (coverage.undocumented > 0)
92
- parts.push(`${coverage.undocumented} undocumented`);
93
- log(`${COLORS.blue}TSDoc${COLORS.reset}: ${coverage.percentage}% coverage (${parts.join(", ")} of ${coverage.total} total)`);
94
- }
95
- function resolveBaseRef() {
96
- const candidates = [
97
- "origin/main",
98
- "main",
99
- "origin/trunk",
100
- "trunk",
101
- "origin/master",
102
- "master"
103
- ];
104
- for (const candidate of candidates) {
105
- const resolved = runGit(["rev-parse", "--verify", "--quiet", candidate]);
106
- if (resolved.ok) {
107
- return candidate;
108
- }
109
- }
110
- return;
111
- }
112
- function changedFilesFromRange(range) {
113
- const result = runGit(["diff", "--name-only", "--diff-filter=d", range]);
114
- return {
115
- ok: result.ok,
116
- files: result.lines
117
- };
118
- }
119
- function getChangedFilesForPush() {
120
- const upstream = runGit([
121
- "rev-parse",
122
- "--abbrev-ref",
123
- "--symbolic-full-name",
124
- "@{upstream}"
125
- ]);
126
- if (upstream.ok && upstream.lines[0]) {
127
- const rangeResult = changedFilesFromRange(`${upstream.lines[0]}...HEAD`);
128
- if (rangeResult.ok) {
129
- return {
130
- files: rangeResult.files,
131
- deterministic: true,
132
- source: "upstream"
133
- };
134
- }
135
- }
136
- const baseRef = resolveBaseRef();
137
- if (baseRef) {
138
- const rangeResult = changedFilesFromRange(`${baseRef}...HEAD`);
139
- if (rangeResult.ok) {
140
- return {
141
- files: rangeResult.files,
142
- deterministic: true,
143
- source: "baseRef"
144
- };
145
- }
146
- }
147
- return {
148
- files: [],
149
- deterministic: false,
150
- source: "undetermined"
151
- };
152
- }
153
- function maybeSkipForRedPhase(reason, branch) {
154
- const changedFiles = getChangedFilesForPush();
155
- if (!changedFiles.deterministic) {
156
- log(`${COLORS.yellow}RED-phase bypass denied${COLORS.reset}: could not determine full push diff range`);
157
- log("Running strict verification.");
158
- log("");
159
- return false;
160
- }
161
- if (!canBypassRedPhaseByChangedFiles(changedFiles)) {
162
- log(`${COLORS.yellow}RED-phase bypass denied${COLORS.reset}: changed files are not test-only`);
163
- if (changedFiles.files.length > 0) {
164
- log(`Changed files (${changedFiles.source}): ${changedFiles.files.join(", ")}`);
165
- } else {
166
- log(`No changed files detected in ${changedFiles.source} range. Running strict verification.`);
167
- }
168
- log("");
169
- return false;
170
- }
171
- if (reason === "branch") {
172
- log(`${COLORS.yellow}TDD RED phase${COLORS.reset} detected: ${COLORS.blue}${branch}${COLORS.reset}`);
173
- } else {
174
- log(`${COLORS.yellow}Scaffold branch${COLORS.reset} with RED phase branch in context: ${COLORS.blue}${branch}${COLORS.reset}`);
175
- }
176
- log(`${COLORS.yellow}Skipping strict verification${COLORS.reset} - changed files are test-only`);
177
- log(`Diff source: ${changedFiles.source}`);
178
- log("");
179
- log("Remember: GREEN phase (implementation) must make these tests pass!");
180
- return true;
181
- }
182
- function hasRedPhaseBranchInContext(currentBranch) {
183
- let branches = [];
184
- try {
185
- const gtResult = Bun.spawnSync(["gt", "ls"], { stderr: "pipe" });
186
- if (gtResult.exitCode === 0) {
187
- branches = gtResult.stdout.toString().split(`
188
- `).map((line) => line.replace(/^[\u2502\u251C\u2514\u2500\u25C9\u25EF ]*/g, "").replace(/ \(.*/, "")).filter(Boolean);
189
- }
190
- } catch {}
191
- if (branches.length === 0) {
192
- const gitResult = Bun.spawnSync([
193
- "git",
194
- "branch",
195
- "--list",
196
- "cli/*",
197
- "types/*",
198
- "contracts/*"
199
- ]);
200
- branches = gitResult.stdout.toString().split(`
201
- `).map((line) => line.replace(/^[* ]+/, "")).filter(Boolean);
202
- }
203
- for (const branch of branches) {
204
- if (branch === currentBranch)
205
- continue;
206
- if (isRedPhaseBranch(branch))
207
- return true;
208
- }
209
- return false;
210
- }
211
- function createVerificationPlan(scripts) {
212
- if (scripts["verify:ci"]) {
213
- return { ok: true, scripts: ["verify:ci"], source: "verify:ci" };
214
- }
215
- const requiredScripts = ["typecheck", "build", "test"];
216
- const missingRequired = requiredScripts.filter((name) => !scripts[name]);
217
- const checkOrLint = scripts["check"] ? "check" : scripts["lint"] ? "lint" : undefined;
218
- if (!checkOrLint || missingRequired.length > 0) {
219
- const missing = checkOrLint ? missingRequired : [...missingRequired, "check|lint"];
220
- return {
221
- ok: false,
222
- error: `Missing required scripts for strict pre-push verification: ${missing.join(", ")}`
223
- };
224
- }
225
- return {
226
- ok: true,
227
- scripts: ["typecheck", checkOrLint, "build", "test"],
228
- source: "fallback"
229
- };
230
- }
231
- function readPackageScripts(cwd = process.cwd()) {
232
- const packageJsonPath = join(cwd, "package.json");
233
- if (!existsSync(packageJsonPath)) {
234
- return {};
235
- }
236
- try {
237
- const parsed = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
238
- const scripts = parsed.scripts ?? {};
239
- const normalized = {};
240
- for (const [name, value] of Object.entries(scripts)) {
241
- if (typeof value === "string") {
242
- normalized[name] = value;
243
- }
244
- }
245
- return normalized;
246
- } catch {
247
- return {};
248
- }
249
- }
250
- function runScript(scriptName) {
251
- log("");
252
- log(`Running: ${COLORS.blue}bun run ${scriptName}${COLORS.reset}`);
253
- const result = Bun.spawnSync(["bun", "run", scriptName], {
254
- stdio: ["inherit", "inherit", "inherit"]
255
- });
256
- return result.exitCode === 0;
257
- }
258
- async function runPrePush(options = {}) {
259
- log(`${COLORS.blue}Pre-push verify${COLORS.reset} (TDD-aware)`);
260
- log("");
261
- const branch = getCurrentBranch();
262
- if (isReleaseBranch(branch)) {
263
- log(`${COLORS.yellow}Release branch detected${COLORS.reset}: ${COLORS.blue}${branch}${COLORS.reset}`);
264
- log(`${COLORS.yellow}Skipping strict verification${COLORS.reset} for automated changeset release push`);
265
- process.exit(0);
266
- }
267
- if (isRedPhaseBranch(branch)) {
268
- if (maybeSkipForRedPhase("branch", branch)) {
269
- process.exit(0);
270
- }
271
- }
272
- if (isScaffoldBranch(branch)) {
273
- if (hasRedPhaseBranchInContext(branch)) {
274
- if (maybeSkipForRedPhase("context", branch)) {
275
- process.exit(0);
276
- }
277
- }
278
- }
279
- if (options.force) {
280
- log(`${COLORS.yellow}Force flag set${COLORS.reset} - skipping strict verification`);
281
- process.exit(0);
282
- }
283
- const plan = createVerificationPlan(readPackageScripts());
284
- if (!plan.ok) {
285
- log(`${COLORS.red}Strict pre-push verification is not configured${COLORS.reset}`);
286
- log(plan.error);
287
- log("");
288
- log("Add one of:");
289
- log(" - verify:ci");
290
- log(" - typecheck + (check or lint) + build + test");
291
- process.exit(1);
292
- }
293
- log(`Running strict verification for branch: ${COLORS.blue}${branch}${COLORS.reset}`);
294
- if (plan.source === "verify:ci") {
295
- log("Using `verify:ci` script.");
296
- } else {
297
- log(`Using fallback scripts: ${plan.scripts.join(" -> ")}`);
298
- }
299
- for (const scriptName of plan.scripts) {
300
- if (runScript(scriptName)) {
301
- continue;
302
- }
303
- log("");
304
- log(`${COLORS.red}Verification failed${COLORS.reset} on script: ${scriptName}`);
305
- log("");
306
- log("If this is intentional TDD RED phase work, name your branch:");
307
- log(" - feature-tests");
308
- log(" - feature/tests");
309
- log(" - feature_tests");
310
- process.exit(1);
311
- }
312
- const changedFiles = getChangedFilesForPush();
313
- if (hasPackageSourceChanges(changedFiles)) {
314
- try {
315
- await printTsdocSummary();
316
- } catch {}
317
- }
318
- log("");
319
- log(`${COLORS.green}Strict verification passed${COLORS.reset}`);
320
- process.exit(0);
321
- }
322
-
323
- export { isRedPhaseBranch, isScaffoldBranch, isReleaseBranch, isTestOnlyPath, areFilesTestOnly, canBypassRedPhaseByChangedFiles, hasPackageSourceChanges, createVerificationPlan, runPrePush };
@@ -1,21 +0,0 @@
1
- // @bun
2
- // packages/tooling/src/cli/fix.ts
3
- function buildFixCommand(options) {
4
- const cmd = ["ultracite", "fix"];
5
- if (options.paths && options.paths.length > 0) {
6
- cmd.push(...options.paths);
7
- }
8
- return cmd;
9
- }
10
- async function runFix(paths = []) {
11
- const cmd = buildFixCommand({ paths });
12
- process.stdout.write(`Running: bun x ${cmd.join(" ")}
13
- `);
14
- const proc = Bun.spawn(["bun", "x", ...cmd], {
15
- stdio: ["inherit", "inherit", "inherit"]
16
- });
17
- const exitCode = await proc.exited;
18
- process.exit(exitCode);
19
- }
20
-
21
- export { buildFixCommand, runFix };
@@ -1,3 +0,0 @@
1
- /** Package version, read from package.json at load time. */
2
- declare const VERSION: string;
3
- export { VERSION };
@@ -1,146 +0,0 @@
1
- // @bun
2
- // packages/tooling/src/cli/upgrade-bun.ts
3
- import { existsSync, readFileSync, writeFileSync } from "fs";
4
- import { join } from "path";
5
- var COLORS = {
6
- reset: "\x1B[0m",
7
- red: "\x1B[31m",
8
- green: "\x1B[32m",
9
- yellow: "\x1B[33m",
10
- blue: "\x1B[34m"
11
- };
12
- function log(msg) {
13
- process.stdout.write(`${msg}
14
- `);
15
- }
16
- function info(msg) {
17
- process.stdout.write(`${COLORS.blue}\u25B8${COLORS.reset} ${msg}
18
- `);
19
- }
20
- function success(msg) {
21
- process.stdout.write(`${COLORS.green}\u2713${COLORS.reset} ${msg}
22
- `);
23
- }
24
- function warn(msg) {
25
- process.stdout.write(`${COLORS.yellow}!${COLORS.reset} ${msg}
26
- `);
27
- }
28
- async function fetchLatestVersion() {
29
- const response = await fetch("https://api.github.com/repos/oven-sh/bun/releases/latest");
30
- const data = await response.json();
31
- const match = data.tag_name.match(/bun-v(.+)/);
32
- if (!match?.[1]) {
33
- throw new Error(`Could not parse version from tag: ${data.tag_name}`);
34
- }
35
- return match[1];
36
- }
37
- function findPackageJsonFiles(dir) {
38
- const results = [];
39
- const glob = new Bun.Glob("**/package.json");
40
- for (const path of glob.scanSync({ cwd: dir })) {
41
- if (!path.includes("node_modules")) {
42
- results.push(join(dir, path));
43
- }
44
- }
45
- return results;
46
- }
47
- function updateEnginesBun(filePath, version) {
48
- const content = readFileSync(filePath, "utf-8");
49
- const pattern = /"bun":\s*">=[\d.]+"/;
50
- if (!pattern.test(content)) {
51
- return false;
52
- }
53
- const updated = content.replace(pattern, `"bun": ">=${version}"`);
54
- if (updated !== content) {
55
- writeFileSync(filePath, updated);
56
- return true;
57
- }
58
- return false;
59
- }
60
- function updateTypesBun(filePath, version) {
61
- const content = readFileSync(filePath, "utf-8");
62
- const pattern = /"@types\/bun":\s*"\^[\d.]+"/;
63
- if (!pattern.test(content)) {
64
- return false;
65
- }
66
- const updated = content.replace(pattern, `"@types/bun": "^${version}"`);
67
- if (updated !== content) {
68
- writeFileSync(filePath, updated);
69
- return true;
70
- }
71
- return false;
72
- }
73
- async function runUpgradeBun(targetVersion, options = {}) {
74
- const cwd = process.cwd();
75
- const bunVersionFile = join(cwd, ".bun-version");
76
- let version = targetVersion;
77
- if (!version) {
78
- info("Fetching latest Bun version...");
79
- version = await fetchLatestVersion();
80
- log(`Latest version: ${version}`);
81
- }
82
- const currentVersion = existsSync(bunVersionFile) ? readFileSync(bunVersionFile, "utf-8").trim() : "unknown";
83
- log(`Current version: ${currentVersion}`);
84
- if (currentVersion === version) {
85
- success(`Already on version ${version}`);
86
- return;
87
- }
88
- log("");
89
- info(`Upgrading Bun: ${currentVersion} \u2192 ${version}`);
90
- log("");
91
- writeFileSync(bunVersionFile, `${version}
92
- `);
93
- success("Updated .bun-version");
94
- const packageFiles = findPackageJsonFiles(cwd);
95
- info("Updating engines.bun...");
96
- for (const file of packageFiles) {
97
- if (updateEnginesBun(file, version)) {
98
- log(` ${file.replace(`${cwd}/`, "")}`);
99
- }
100
- }
101
- info("Updating @types/bun...");
102
- for (const file of packageFiles) {
103
- if (updateTypesBun(file, version)) {
104
- log(` ${file.replace(`${cwd}/`, "")}`);
105
- }
106
- }
107
- if (options.install !== false) {
108
- log("");
109
- info(`Installing Bun ${version}...`);
110
- const installResult = Bun.spawnSync([
111
- "bash",
112
- "-c",
113
- `curl -fsSL https://bun.sh/install | bash -s "bun-v${version}"`
114
- ]);
115
- if (installResult.exitCode !== 0) {
116
- warn("Could not install Bun automatically");
117
- log("Install manually: curl -fsSL https://bun.sh/install | bash");
118
- } else {
119
- success(`Bun ${version} installed`);
120
- log("");
121
- info("Updating lockfile...");
122
- const bunInstall = Bun.spawnSync(["bun", "install"], {
123
- cwd,
124
- env: {
125
- ...process.env,
126
- BUN_INSTALL: `${process.env["HOME"]}/.bun`,
127
- PATH: `${process.env["HOME"]}/.bun/bin:${process.env["PATH"]}`
128
- }
129
- });
130
- if (bunInstall.exitCode === 0) {
131
- success("Lockfile updated");
132
- } else {
133
- warn("Could not update lockfile - run 'bun install' manually");
134
- }
135
- }
136
- }
137
- log("");
138
- success("Done! Changes ready to commit:");
139
- log(" - .bun-version");
140
- log(" - package.json files (engines.bun, @types/bun)");
141
- log(" - bun.lock");
142
- log("");
143
- log(`Commit with: git add -A && git commit -m 'chore: upgrade Bun to ${version}'`);
144
- }
145
-
146
- export { runUpgradeBun };
@@ -1,184 +0,0 @@
1
- // @bun
2
- // packages/tooling/src/cli/check-changeset.ts
3
- import { existsSync, readFileSync } from "fs";
4
- import { join } from "path";
5
- function getChangedPackagePaths(files) {
6
- const packageNames = new Set;
7
- const pattern = /^packages\/([^/]+)\/src\//;
8
- for (const file of files) {
9
- const match = pattern.exec(file);
10
- if (match?.[1]) {
11
- packageNames.add(match[1]);
12
- }
13
- }
14
- return [...packageNames].sort();
15
- }
16
- function getChangedChangesetFiles(files) {
17
- const pattern = /^\.changeset\/([^/]+\.md)$/;
18
- const results = [];
19
- for (const file of files) {
20
- const match = pattern.exec(file);
21
- if (match?.[1] && match[1] !== "README.md") {
22
- results.push(match[1]);
23
- }
24
- }
25
- return results.sort();
26
- }
27
- function checkChangesetRequired(changedPackages, changesetFiles) {
28
- if (changedPackages.length === 0) {
29
- return { ok: true, missingFor: [] };
30
- }
31
- if (changesetFiles.length > 0) {
32
- return { ok: true, missingFor: [] };
33
- }
34
- return { ok: false, missingFor: changedPackages };
35
- }
36
- function parseIgnoredPackagesFromChangesetConfig(jsonContent) {
37
- try {
38
- const parsed = JSON.parse(jsonContent);
39
- if (!Array.isArray(parsed.ignore)) {
40
- return [];
41
- }
42
- return parsed.ignore.filter((entry) => typeof entry === "string");
43
- } catch {
44
- return [];
45
- }
46
- }
47
- function parseChangesetFrontmatterPackageNames(markdownContent) {
48
- const frontmatterMatch = /^---\r?\n([\s\S]*?)\r?\n---/.exec(markdownContent);
49
- if (!frontmatterMatch?.[1]) {
50
- return [];
51
- }
52
- const packages = new Set;
53
- for (const line of frontmatterMatch[1].split(/\r?\n/)) {
54
- const trimmed = line.trim();
55
- const match = /^(["']?)(@[^"':\s]+\/[^"':\s]+)\1\s*:/.exec(trimmed);
56
- if (match?.[2]) {
57
- packages.add(match[2]);
58
- }
59
- }
60
- return [...packages].sort();
61
- }
62
- function findIgnoredPackageReferences(input) {
63
- if (input.ignoredPackages.length === 0 || input.changesetFiles.length === 0) {
64
- return [];
65
- }
66
- const ignored = new Set(input.ignoredPackages);
67
- const results = [];
68
- for (const file of input.changesetFiles) {
69
- const content = input.readChangesetFile(file);
70
- const referencedPackages = parseChangesetFrontmatterPackageNames(content);
71
- const invalidReferences = referencedPackages.filter((pkg) => ignored.has(pkg));
72
- if (invalidReferences.length > 0) {
73
- results.push({ file, packages: invalidReferences.sort() });
74
- }
75
- }
76
- return results.sort((a, b) => a.file.localeCompare(b.file));
77
- }
78
- function loadIgnoredPackages(cwd) {
79
- const configPath = join(cwd, ".changeset", "config.json");
80
- if (!existsSync(configPath)) {
81
- return [];
82
- }
83
- try {
84
- return parseIgnoredPackagesFromChangesetConfig(readFileSync(configPath, "utf-8"));
85
- } catch {
86
- return [];
87
- }
88
- }
89
- function getIgnoredReferencesForChangedChangesets(cwd, changesetFiles) {
90
- const ignoredPackages = loadIgnoredPackages(cwd);
91
- return findIgnoredPackageReferences({
92
- changesetFiles,
93
- ignoredPackages,
94
- readChangesetFile: (filename) => {
95
- try {
96
- return readFileSync(join(cwd, ".changeset", filename), "utf-8");
97
- } catch {
98
- return "";
99
- }
100
- }
101
- });
102
- }
103
- var COLORS = {
104
- reset: "\x1B[0m",
105
- red: "\x1B[31m",
106
- green: "\x1B[32m",
107
- yellow: "\x1B[33m",
108
- blue: "\x1B[34m",
109
- dim: "\x1B[2m"
110
- };
111
- async function runCheckChangeset(options = {}) {
112
- if (options.skip || process.env["NO_CHANGESET"] === "1") {
113
- process.stdout.write(`${COLORS.dim}check-changeset skipped (NO_CHANGESET=1)${COLORS.reset}
114
- `);
115
- process.exit(0);
116
- }
117
- if (process.env["GITHUB_EVENT_NAME"] === "push") {
118
- process.stdout.write(`${COLORS.dim}check-changeset skipped (push event)${COLORS.reset}
119
- `);
120
- process.exit(0);
121
- }
122
- const cwd = process.cwd();
123
- let changedFiles;
124
- try {
125
- const proc = Bun.spawnSync(["git", "diff", "--name-only", "origin/main...HEAD"], { cwd });
126
- if (proc.exitCode !== 0) {
127
- process.exit(0);
128
- }
129
- changedFiles = proc.stdout.toString().trim().split(`
130
- `).filter((line) => line.length > 0);
131
- } catch {
132
- process.exit(0);
133
- }
134
- const changedPackages = getChangedPackagePaths(changedFiles);
135
- if (changedPackages.length === 0) {
136
- process.stdout.write(`${COLORS.green}No package source changes detected.${COLORS.reset}
137
- `);
138
- process.exit(0);
139
- }
140
- const changesetFiles = getChangedChangesetFiles(changedFiles);
141
- const check = checkChangesetRequired(changedPackages, changesetFiles);
142
- if (!check.ok) {
143
- process.stderr.write(`${COLORS.red}Missing changeset!${COLORS.reset}
144
-
145
- `);
146
- process.stderr.write(`The following packages have source changes but no changeset:
147
-
148
- `);
149
- for (const pkg of check.missingFor) {
150
- process.stderr.write(` ${COLORS.yellow}@outfitter/${pkg}${COLORS.reset}
151
- `);
152
- }
153
- process.stderr.write(`
154
- Run ${COLORS.blue}bun run changeset${COLORS.reset} to add a changeset, ` + `or add the ${COLORS.blue}no-changeset${COLORS.reset} label to skip.
155
- `);
156
- process.exit(1);
157
- }
158
- const ignoredReferences = getIgnoredReferencesForChangedChangesets(cwd, changesetFiles);
159
- if (ignoredReferences.length > 0) {
160
- process.stderr.write(`${COLORS.red}Invalid changeset package reference(s).${COLORS.reset}
161
-
162
- `);
163
- process.stderr.write(`Changesets must not reference packages listed in .changeset/config.json ignore:
164
-
165
- `);
166
- for (const reference of ignoredReferences) {
167
- process.stderr.write(` ${COLORS.yellow}${reference.file}${COLORS.reset}
168
- `);
169
- for (const pkg of reference.packages) {
170
- process.stderr.write(` - ${pkg}
171
- `);
172
- }
173
- }
174
- process.stderr.write(`
175
- Update the affected changeset files to remove ignored packages before merging.
176
- `);
177
- process.exit(1);
178
- }
179
- process.stdout.write(`${COLORS.green}Changeset found for ${changedPackages.length} changed package(s).${COLORS.reset}
180
- `);
181
- process.exit(0);
182
- }
183
-
184
- export { getChangedPackagePaths, getChangedChangesetFiles, checkChangesetRequired, parseIgnoredPackagesFromChangesetConfig, parseChangesetFrontmatterPackageNames, findIgnoredPackageReferences, runCheckChangeset };
@@ -1,19 +0,0 @@
1
- // @bun
2
- // packages/tooling/src/version.ts
3
- import { readFileSync } from "fs";
4
- import { createRequire } from "module";
5
- var DEFAULT_VERSION = "0.0.0";
6
- function readPackageVersion() {
7
- try {
8
- const require2 = createRequire(import.meta.url);
9
- const pkgPath = require2.resolve("@outfitter/tooling/package.json");
10
- const packageJson = JSON.parse(readFileSync(pkgPath, "utf8"));
11
- if (typeof packageJson.version === "string" && packageJson.version.length > 0) {
12
- return packageJson.version;
13
- }
14
- } catch {}
15
- return DEFAULT_VERSION;
16
- }
17
- var VERSION = readPackageVersion();
18
-
19
- export { VERSION };
@@ -1,4 +0,0 @@
1
- // @bun
2
- var __require = import.meta.require;
3
-
4
- export { __require };