@outfitter/tooling 0.3.3 → 0.3.4
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/.markdownlint-cli2.jsonc +55 -55
- package/README.md +21 -21
- package/dist/bun-version-compat.d.ts +2 -0
- package/dist/bun-version-compat.js +10 -0
- package/dist/cli/check-boundary-invocations.d.ts +34 -0
- package/dist/cli/check-boundary-invocations.js +14 -0
- package/dist/cli/check-bunup-registry.d.ts +36 -0
- package/dist/cli/check-bunup-registry.js +12 -0
- package/dist/cli/check-changeset.d.ts +66 -0
- package/dist/cli/check-changeset.js +20 -0
- package/dist/cli/check-clean-tree.d.ts +36 -0
- package/dist/cli/check-clean-tree.js +14 -0
- package/dist/cli/check-exports.d.ts +2 -0
- package/dist/cli/check-exports.js +14 -0
- package/dist/cli/check-markdown-links.d.ts +42 -0
- package/dist/cli/check-markdown-links.js +13 -0
- package/dist/cli/check-readme-imports.d.ts +60 -0
- package/dist/{shared/chunk-7tdgbqb0.js → cli/check-readme-imports.js} +7 -6
- package/dist/cli/check-tsdoc.d.ts +2 -0
- package/dist/cli/check-tsdoc.js +36 -0
- package/dist/cli/check.d.ts +19 -0
- package/dist/cli/check.js +10 -0
- package/dist/cli/fix.d.ts +19 -0
- package/dist/cli/fix.js +10 -0
- package/dist/cli/index.js +49 -1218
- package/dist/cli/init.d.ts +31 -0
- package/dist/cli/init.js +12 -0
- package/dist/cli/pre-push.d.ts +60 -0
- package/dist/cli/pre-push.js +27 -0
- package/dist/cli/upgrade-bun.d.ts +8 -0
- package/dist/cli/upgrade-bun.js +9 -0
- package/dist/index.d.ts +6 -186
- package/dist/index.js +4 -42
- package/dist/registry/build.d.ts +4 -0
- package/dist/registry/build.js +279 -0
- package/dist/registry/index.d.ts +3 -0
- package/dist/registry/index.js +1 -0
- package/dist/registry/schema.d.ts +2 -0
- package/dist/registry/schema.js +28 -0
- package/dist/shared/@outfitter/tooling-1hez6j9d.js +21 -0
- package/dist/shared/@outfitter/tooling-6cxfdx0q.js +187 -0
- package/dist/shared/{chunk-cmde0fwx.js → @outfitter/tooling-875svjnz.js} +16 -31
- package/dist/shared/@outfitter/tooling-9ram55dd.js +69 -0
- package/dist/shared/@outfitter/tooling-9vs606gq.d.ts +3 -0
- package/dist/shared/@outfitter/tooling-a4bfx4be.js +21 -0
- package/dist/shared/@outfitter/tooling-amrbp7cm.js +102 -0
- package/dist/shared/@outfitter/tooling-ctmgnap5.js +19 -0
- package/dist/shared/@outfitter/tooling-d363b88r.js +349 -0
- package/dist/shared/@outfitter/tooling-gcdvsqqp.js +73 -0
- package/dist/shared/@outfitter/tooling-h04te11c.js +231 -0
- package/dist/shared/@outfitter/tooling-ja1zg5yc.js +214 -0
- package/dist/shared/@outfitter/tooling-jnrs9rqd.js +4 -0
- package/dist/shared/@outfitter/tooling-mkynjra9.js +23 -0
- package/dist/shared/@outfitter/tooling-njw4z34x.d.ts +140 -0
- package/dist/shared/@outfitter/tooling-pq47jv6t.js +213 -0
- package/dist/shared/@outfitter/tooling-sjm8nebx.d.ts +109 -0
- package/dist/shared/@outfitter/tooling-vjmhvpjq.d.ts +29 -0
- package/dist/shared/@outfitter/tooling-wesswf21.d.ts +59 -0
- package/dist/shared/@outfitter/tooling-wwm97f47.js +81 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +8 -0
- package/package.json +134 -131
- package/registry/registry.json +17 -10
- package/tsconfig.preset.bun.json +5 -5
- package/tsconfig.preset.json +33 -33
- package/biome.json +0 -81
- package/dist/shared/chunk-3s189drz.js +0 -4
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import"../shared/@outfitter/tooling-jnrs9rqd.js";
|
|
3
|
+
|
|
4
|
+
// packages/tooling/src/registry/schema.ts
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
var FileEntrySchema = z.object({
|
|
7
|
+
path: z.string().min(1),
|
|
8
|
+
content: z.string(),
|
|
9
|
+
executable: z.boolean().optional(),
|
|
10
|
+
template: z.boolean().optional()
|
|
11
|
+
});
|
|
12
|
+
var BlockSchema = z.object({
|
|
13
|
+
name: z.string().min(1),
|
|
14
|
+
description: z.string().min(1),
|
|
15
|
+
files: z.array(FileEntrySchema).optional(),
|
|
16
|
+
dependencies: z.record(z.string(), z.string()).optional(),
|
|
17
|
+
devDependencies: z.record(z.string(), z.string()).optional(),
|
|
18
|
+
extends: z.array(z.string()).optional()
|
|
19
|
+
});
|
|
20
|
+
var RegistrySchema = z.object({
|
|
21
|
+
version: z.string(),
|
|
22
|
+
blocks: z.record(z.string(), BlockSchema)
|
|
23
|
+
});
|
|
24
|
+
export {
|
|
25
|
+
RegistrySchema,
|
|
26
|
+
FileEntrySchema,
|
|
27
|
+
BlockSchema
|
|
28
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
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.exitCode = exitCode;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { buildFixCommand, runFix };
|
|
@@ -0,0 +1,187 @@
|
|
|
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].toSorted();
|
|
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.toSorted();
|
|
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].toSorted();
|
|
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.toSorted() });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return results.toSorted((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.exitCode = 0;
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (process.env["GITHUB_EVENT_NAME"] === "push") {
|
|
119
|
+
process.stdout.write(`${COLORS.dim}check-changeset skipped (push event)${COLORS.reset}
|
|
120
|
+
`);
|
|
121
|
+
process.exitCode = 0;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const cwd = process.cwd();
|
|
125
|
+
let changedFiles;
|
|
126
|
+
try {
|
|
127
|
+
const proc = Bun.spawnSync(["git", "diff", "--name-only", "origin/main...HEAD"], { cwd });
|
|
128
|
+
if (proc.exitCode !== 0) {
|
|
129
|
+
process.exitCode = 0;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
changedFiles = proc.stdout.toString().trim().split(`
|
|
133
|
+
`).filter((line) => line.length > 0);
|
|
134
|
+
} catch {
|
|
135
|
+
process.exitCode = 0;
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const changedPackages = getChangedPackagePaths(changedFiles);
|
|
139
|
+
if (changedPackages.length === 0) {
|
|
140
|
+
process.stdout.write(`${COLORS.green}No package source changes detected.${COLORS.reset}
|
|
141
|
+
`);
|
|
142
|
+
process.exitCode = 0;
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const changesetFiles = getChangedChangesetFiles(changedFiles);
|
|
146
|
+
const check = checkChangesetRequired(changedPackages, changesetFiles);
|
|
147
|
+
if (!check.ok) {
|
|
148
|
+
process.stderr.write(`${COLORS.yellow}No changeset found.${COLORS.reset} ` + "Consider adding one with `bun run changeset` for a custom changelog entry.\n\n");
|
|
149
|
+
process.stderr.write(`Packages with source changes:
|
|
150
|
+
|
|
151
|
+
`);
|
|
152
|
+
for (const pkg of check.missingFor) {
|
|
153
|
+
process.stderr.write(` ${COLORS.yellow}@outfitter/${pkg}${COLORS.reset}
|
|
154
|
+
`);
|
|
155
|
+
}
|
|
156
|
+
process.stderr.write(`
|
|
157
|
+
Run ${COLORS.blue}bun run changeset${COLORS.reset} for a custom changelog entry, ` + `or add ${COLORS.blue}release:none${COLORS.reset} to skip.
|
|
158
|
+
`);
|
|
159
|
+
}
|
|
160
|
+
const ignoredReferences = getIgnoredReferencesForChangedChangesets(cwd, changesetFiles);
|
|
161
|
+
if (ignoredReferences.length > 0) {
|
|
162
|
+
process.stderr.write(`${COLORS.red}Invalid changeset package reference(s).${COLORS.reset}
|
|
163
|
+
|
|
164
|
+
`);
|
|
165
|
+
process.stderr.write(`Changesets must not reference packages listed in .changeset/config.json ignore:
|
|
166
|
+
|
|
167
|
+
`);
|
|
168
|
+
for (const reference of ignoredReferences) {
|
|
169
|
+
process.stderr.write(` ${COLORS.yellow}${reference.file}${COLORS.reset}
|
|
170
|
+
`);
|
|
171
|
+
for (const pkg of reference.packages) {
|
|
172
|
+
process.stderr.write(` - ${pkg}
|
|
173
|
+
`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
process.stderr.write(`
|
|
177
|
+
Update the affected changeset files to remove ignored packages before merging.
|
|
178
|
+
`);
|
|
179
|
+
process.exitCode = 1;
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
process.stdout.write(`${COLORS.green}Changeset found for ${changedPackages.length} changed package(s).${COLORS.reset}
|
|
183
|
+
`);
|
|
184
|
+
process.exitCode = 0;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export { getChangedPackagePaths, getChangedChangesetFiles, checkChangesetRequired, parseIgnoredPackagesFromChangesetConfig, parseChangesetFrontmatterPackageNames, findIgnoredPackageReferences, runCheckChangeset };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
// @bun
|
|
1
2
|
import {
|
|
2
3
|
__require
|
|
3
|
-
} from "./
|
|
4
|
+
} from "./tooling-jnrs9rqd.js";
|
|
4
5
|
|
|
5
|
-
// src/cli/check-tsdoc.ts
|
|
6
|
-
import { resolve } from "
|
|
6
|
+
// packages/tooling/src/cli/check-tsdoc.ts
|
|
7
|
+
import { resolve } from "path";
|
|
7
8
|
import ts from "typescript";
|
|
8
9
|
import { z } from "zod";
|
|
9
10
|
var coverageLevelSchema = z.enum([
|
|
@@ -174,7 +175,7 @@ function bar(percentage, width = 20) {
|
|
|
174
175
|
const filled = Math.round(percentage / 100 * width);
|
|
175
176
|
const empty = width - filled;
|
|
176
177
|
const color = percentage >= 80 ? COLORS.green : percentage >= 50 ? COLORS.yellow : COLORS.red;
|
|
177
|
-
return `${color}${"
|
|
178
|
+
return `${color}${"\u2588".repeat(filled)}${COLORS.dim}${"\u2591".repeat(empty)}${COLORS.reset}`;
|
|
178
179
|
}
|
|
179
180
|
function discoverPackages(cwd) {
|
|
180
181
|
const packages = [];
|
|
@@ -195,7 +196,7 @@ function discoverPackages(cwd) {
|
|
|
195
196
|
const pkgRoot = resolve(cwd, rootDir, pkgDir);
|
|
196
197
|
let pkgName = pkgDir;
|
|
197
198
|
try {
|
|
198
|
-
const pkgJson = JSON.parse(__require("
|
|
199
|
+
const pkgJson = JSON.parse(__require("fs").readFileSync(resolve(pkgRoot, "package.json"), "utf-8"));
|
|
199
200
|
if (pkgJson.name)
|
|
200
201
|
pkgName = pkgJson.name;
|
|
201
202
|
} catch {}
|
|
@@ -209,10 +210,10 @@ function discoverPackages(cwd) {
|
|
|
209
210
|
if (packages.length === 0) {
|
|
210
211
|
const entryPoint = resolve(cwd, "src/index.ts");
|
|
211
212
|
try {
|
|
212
|
-
__require("
|
|
213
|
+
__require("fs").accessSync(entryPoint);
|
|
213
214
|
let pkgName = "root";
|
|
214
215
|
try {
|
|
215
|
-
const pkgJson = JSON.parse(__require("
|
|
216
|
+
const pkgJson = JSON.parse(__require("fs").readFileSync(resolve(cwd, "package.json"), "utf-8"));
|
|
216
217
|
if (pkgJson.name)
|
|
217
218
|
pkgName = pkgJson.name;
|
|
218
219
|
} catch {}
|
|
@@ -224,7 +225,7 @@ function discoverPackages(cwd) {
|
|
|
224
225
|
seenEntryPoints.add(entryPoint);
|
|
225
226
|
} catch {}
|
|
226
227
|
}
|
|
227
|
-
return packages.
|
|
228
|
+
return packages.toSorted((a, b) => a.name.localeCompare(b.name));
|
|
228
229
|
}
|
|
229
230
|
function collectReExportedSourceFiles(sourceFile, program, pkgPath) {
|
|
230
231
|
const result = [];
|
|
@@ -256,7 +257,7 @@ function collectReExportedSourceFiles(sourceFile, program, pkgPath) {
|
|
|
256
257
|
}
|
|
257
258
|
function analyzePackage(pkg, workspaceCwd) {
|
|
258
259
|
try {
|
|
259
|
-
__require("
|
|
260
|
+
__require("fs").accessSync(pkg.entryPoint);
|
|
260
261
|
} catch {
|
|
261
262
|
return {
|
|
262
263
|
name: pkg.name,
|
|
@@ -271,7 +272,7 @@ function analyzePackage(pkg, workspaceCwd) {
|
|
|
271
272
|
}
|
|
272
273
|
let tsconfigPath = resolve(pkg.path, "tsconfig.json");
|
|
273
274
|
try {
|
|
274
|
-
__require("
|
|
275
|
+
__require("fs").accessSync(tsconfigPath);
|
|
275
276
|
} catch {
|
|
276
277
|
tsconfigPath = resolve(workspaceCwd, "tsconfig.json");
|
|
277
278
|
}
|
|
@@ -318,7 +319,7 @@ function analyzeCheckTsdoc(options = {}) {
|
|
|
318
319
|
const entryPoint = resolve(absPath, "src/index.ts");
|
|
319
320
|
let name = p;
|
|
320
321
|
try {
|
|
321
|
-
const pkgJson = JSON.parse(__require("
|
|
322
|
+
const pkgJson = JSON.parse(__require("fs").readFileSync(resolve(absPath, "package.json"), "utf-8"));
|
|
322
323
|
if (pkgJson.name)
|
|
323
324
|
name = pkgJson.name;
|
|
324
325
|
} catch {}
|
|
@@ -387,7 +388,8 @@ async function runCheckTsdoc(options = {}) {
|
|
|
387
388
|
` + `Searched: packages/*/src/index.ts, apps/*/src/index.ts, src/index.ts
|
|
388
389
|
` + `Use --package <path> to specify a package path explicitly.
|
|
389
390
|
`);
|
|
390
|
-
process.
|
|
391
|
+
process.exitCode = 1;
|
|
392
|
+
return;
|
|
391
393
|
}
|
|
392
394
|
if (resolveJsonMode(options)) {
|
|
393
395
|
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
@@ -398,24 +400,7 @@ async function runCheckTsdoc(options = {}) {
|
|
|
398
400
|
minCoverage: options.minCoverage
|
|
399
401
|
});
|
|
400
402
|
}
|
|
401
|
-
process.
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// src/version.ts
|
|
405
|
-
import { readFileSync } from "node:fs";
|
|
406
|
-
import { createRequire } from "node:module";
|
|
407
|
-
var DEFAULT_VERSION = "0.0.0";
|
|
408
|
-
function readPackageVersion() {
|
|
409
|
-
try {
|
|
410
|
-
const require2 = createRequire(import.meta.url);
|
|
411
|
-
const pkgPath = require2.resolve("@outfitter/tooling/package.json");
|
|
412
|
-
const packageJson = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
413
|
-
if (typeof packageJson.version === "string" && packageJson.version.length > 0) {
|
|
414
|
-
return packageJson.version;
|
|
415
|
-
}
|
|
416
|
-
} catch {}
|
|
417
|
-
return DEFAULT_VERSION;
|
|
403
|
+
process.exitCode = result.ok ? 0 : 1;
|
|
418
404
|
}
|
|
419
|
-
var VERSION = readPackageVersion();
|
|
420
405
|
|
|
421
|
-
export { coverageLevelSchema, declarationCoverageSchema, packageCoverageSchema, tsDocCheckResultSchema, analyzeSourceFile, calculateCoverage, analyzeCheckTsdoc, printCheckTsdocHuman, runCheckTsdoc
|
|
406
|
+
export { coverageLevelSchema, declarationCoverageSchema, coverageSummarySchema, packageCoverageSchema, tsDocCheckResultSchema, isExportedDeclaration, getDeclarationName, getDeclarationKind, classifyDeclaration, analyzeSourceFile, calculateCoverage, resolveJsonMode, analyzeCheckTsdoc, printCheckTsdocHuman, runCheckTsdoc };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/tooling/src/cli/init.ts
|
|
3
|
+
var FRAMEWORK_DETECTORS = {
|
|
4
|
+
react: ["react", "react-dom"],
|
|
5
|
+
next: ["next"],
|
|
6
|
+
vue: ["vue"],
|
|
7
|
+
nuxt: ["nuxt"],
|
|
8
|
+
svelte: ["svelte"],
|
|
9
|
+
angular: ["@angular/core"],
|
|
10
|
+
solid: ["solid-js"],
|
|
11
|
+
astro: ["astro"],
|
|
12
|
+
remix: ["@remix-run/react"],
|
|
13
|
+
qwik: ["@builder.io/qwik"]
|
|
14
|
+
};
|
|
15
|
+
function detectFrameworks(pkg) {
|
|
16
|
+
const allDeps = {
|
|
17
|
+
...pkg.dependencies,
|
|
18
|
+
...pkg.devDependencies
|
|
19
|
+
};
|
|
20
|
+
const detected = [];
|
|
21
|
+
for (const [framework, packages] of Object.entries(FRAMEWORK_DETECTORS)) {
|
|
22
|
+
if (packages.some((p) => (p in allDeps))) {
|
|
23
|
+
detected.push(framework);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (detected.length === 0) {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
return ["--frameworks", ...detected];
|
|
30
|
+
}
|
|
31
|
+
function buildUltraciteCommand(options) {
|
|
32
|
+
const cmd = [
|
|
33
|
+
"ultracite",
|
|
34
|
+
"init",
|
|
35
|
+
"--linter",
|
|
36
|
+
"oxlint",
|
|
37
|
+
"--pm",
|
|
38
|
+
"bun",
|
|
39
|
+
"--quiet"
|
|
40
|
+
];
|
|
41
|
+
if (options.frameworks && options.frameworks.length > 0) {
|
|
42
|
+
cmd.push("--frameworks", ...options.frameworks);
|
|
43
|
+
}
|
|
44
|
+
return cmd;
|
|
45
|
+
}
|
|
46
|
+
async function runInit(cwd = process.cwd()) {
|
|
47
|
+
const pkgPath = `${cwd}/package.json`;
|
|
48
|
+
const pkgFile = Bun.file(pkgPath);
|
|
49
|
+
if (!await pkgFile.exists()) {
|
|
50
|
+
process.stderr.write(`No package.json found in current directory
|
|
51
|
+
`);
|
|
52
|
+
process.exitCode = 1;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const pkg = await pkgFile.json();
|
|
56
|
+
const frameworkFlags = detectFrameworks(pkg);
|
|
57
|
+
const frameworks = frameworkFlags.length > 0 ? frameworkFlags.slice(1) : [];
|
|
58
|
+
const cmd = buildUltraciteCommand({ frameworks });
|
|
59
|
+
process.stdout.write(`Running: bun x ${cmd.join(" ")}
|
|
60
|
+
`);
|
|
61
|
+
const proc = Bun.spawn(["bun", "x", ...cmd], {
|
|
62
|
+
cwd,
|
|
63
|
+
stdio: ["inherit", "inherit", "inherit"]
|
|
64
|
+
});
|
|
65
|
+
const exitCode = await proc.exited;
|
|
66
|
+
process.exitCode = exitCode;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { detectFrameworks, buildUltraciteCommand, runInit };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/tooling/src/cli/check.ts
|
|
3
|
+
function buildCheckCommand(options) {
|
|
4
|
+
const cmd = ["ultracite", "check"];
|
|
5
|
+
if (options.paths && options.paths.length > 0) {
|
|
6
|
+
cmd.push(...options.paths);
|
|
7
|
+
}
|
|
8
|
+
return cmd;
|
|
9
|
+
}
|
|
10
|
+
async function runCheck(paths = []) {
|
|
11
|
+
const cmd = buildCheckCommand({ 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.exitCode = exitCode;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { buildCheckCommand, runCheck };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/tooling/src/cli/check-boundary-invocations.ts
|
|
3
|
+
import { relative, resolve } from "path";
|
|
4
|
+
var ROOT_RUNS_PACKAGE_SRC = /\bbun(?:x)?\s+(?:run\s+)?(?:\.\.\/|\.\/)?packages\/[^/\s]+\/src\/\S+/;
|
|
5
|
+
var CD_PACKAGE_THEN_RUNS_SRC = /\bcd\s+(?:\.\.\/|\.\/)?packages\/[^/\s]+\s*&&\s*bun(?:x)?\s+(?:run\s+)?(?:\.\.\/|\.\/)?src\/\S+/;
|
|
6
|
+
function detectBoundaryViolation(location) {
|
|
7
|
+
if (ROOT_RUNS_PACKAGE_SRC.test(location.command)) {
|
|
8
|
+
return { ...location, rule: "root-runs-package-src" };
|
|
9
|
+
}
|
|
10
|
+
if (CD_PACKAGE_THEN_RUNS_SRC.test(location.command)) {
|
|
11
|
+
return { ...location, rule: "cd-package-then-runs-src" };
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
function findBoundaryViolations(entries) {
|
|
16
|
+
const violations = [];
|
|
17
|
+
for (const entry of entries) {
|
|
18
|
+
for (const [scriptName, command] of Object.entries(entry.scripts)) {
|
|
19
|
+
const violation = detectBoundaryViolation({
|
|
20
|
+
file: entry.file,
|
|
21
|
+
scriptName,
|
|
22
|
+
command
|
|
23
|
+
});
|
|
24
|
+
if (violation) {
|
|
25
|
+
violations.push(violation);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return violations.toSorted((a, b) => {
|
|
30
|
+
const fileCompare = a.file.localeCompare(b.file);
|
|
31
|
+
if (fileCompare !== 0) {
|
|
32
|
+
return fileCompare;
|
|
33
|
+
}
|
|
34
|
+
return a.scriptName.localeCompare(b.scriptName);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async function readScriptEntries(cwd, options = {}) {
|
|
38
|
+
const entries = [];
|
|
39
|
+
const rootPackagePath = resolve(cwd, "package.json");
|
|
40
|
+
const candidatePaths = [rootPackagePath];
|
|
41
|
+
if (options.appManifestRelativePaths) {
|
|
42
|
+
for (const file of options.appManifestRelativePaths) {
|
|
43
|
+
candidatePaths.push(resolve(cwd, file));
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
const appPackageGlob = new Bun.Glob("apps/*/package.json");
|
|
47
|
+
for (const match of appPackageGlob.scanSync({ cwd })) {
|
|
48
|
+
candidatePaths.push(resolve(cwd, match));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const readPackageJson = options.readPackageJson ?? (async (filePath) => await Bun.file(filePath).json());
|
|
52
|
+
for (const filePath of candidatePaths) {
|
|
53
|
+
const isRootManifest = filePath === rootPackagePath;
|
|
54
|
+
try {
|
|
55
|
+
const pkg = await readPackageJson(filePath);
|
|
56
|
+
if (!pkg.scripts) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
entries.push({
|
|
60
|
+
file: relative(cwd, filePath),
|
|
61
|
+
scripts: pkg.scripts
|
|
62
|
+
});
|
|
63
|
+
} catch (error) {
|
|
64
|
+
if (isRootManifest) {
|
|
65
|
+
const message = error instanceof Error ? error.message : "unknown parse error";
|
|
66
|
+
throw new Error(`Failed to read root package manifest (${filePath}): ${message}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return entries;
|
|
71
|
+
}
|
|
72
|
+
async function runCheckBoundaryInvocations() {
|
|
73
|
+
const cwd = process.cwd();
|
|
74
|
+
let entries;
|
|
75
|
+
try {
|
|
76
|
+
entries = await readScriptEntries(cwd);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
const message = error instanceof Error ? error.message : "unknown read failure";
|
|
79
|
+
process.stderr.write(`Boundary invocation check failed before evaluation: ${message}
|
|
80
|
+
`);
|
|
81
|
+
process.exitCode = 1;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const violations = findBoundaryViolations(entries);
|
|
85
|
+
if (violations.length === 0) {
|
|
86
|
+
process.stdout.write(`No boundary invocation violations detected in root/apps scripts.
|
|
87
|
+
`);
|
|
88
|
+
process.exitCode = 0;
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
process.stderr.write(`Boundary invocation violations detected:
|
|
92
|
+
|
|
93
|
+
`);
|
|
94
|
+
for (const violation of violations) {
|
|
95
|
+
process.stderr.write(`- ${violation.file}#${violation.scriptName}: ${violation.command}
|
|
96
|
+
`);
|
|
97
|
+
}
|
|
98
|
+
process.stderr.write("\nUse canonical command surfaces (e.g. `outfitter repo ...` or package bins) instead of executing packages/*/src directly.\n");
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { detectBoundaryViolation, findBoundaryViolations, readScriptEntries, runCheckBoundaryInvocations };
|
|
@@ -0,0 +1,19 @@
|
|
|
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 };
|