@outfitter/tooling 0.3.4 → 0.3.5

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 (50) hide show
  1. package/README.md +12 -3
  2. package/dist/cli/check-changeset.d.ts +28 -12
  3. package/dist/cli/check-changeset.js +5 -1
  4. package/dist/cli/check-exports.d.ts +2 -1
  5. package/dist/cli/check-exports.js +6 -3
  6. package/dist/cli/check-home-paths.d.ts +31 -0
  7. package/dist/cli/check-home-paths.js +12 -0
  8. package/dist/cli/check-readme-imports.d.ts +2 -1
  9. package/dist/cli/check-tsdoc.d.ts +4 -1
  10. package/dist/cli/check-tsdoc.js +16 -10
  11. package/dist/cli/index.js +16 -4
  12. package/dist/cli/internal/exports-analysis.d.ts +2 -0
  13. package/dist/cli/internal/exports-analysis.js +10 -0
  14. package/dist/cli/internal/exports-fs.d.ts +17 -0
  15. package/dist/cli/internal/exports-fs.js +9 -0
  16. package/dist/cli/internal/pre-push-checks.d.ts +2 -0
  17. package/dist/cli/internal/pre-push-checks.js +37 -0
  18. package/dist/cli/internal/tsdoc-analysis.d.ts +3 -0
  19. package/dist/cli/internal/tsdoc-analysis.js +26 -0
  20. package/dist/cli/internal/tsdoc-formatting.d.ts +3 -0
  21. package/dist/cli/internal/tsdoc-formatting.js +10 -0
  22. package/dist/cli/internal/tsdoc-types.d.ts +2 -0
  23. package/dist/cli/internal/tsdoc-types.js +16 -0
  24. package/dist/cli/pre-push.d.ts +2 -55
  25. package/dist/cli/pre-push.js +6 -4
  26. package/dist/index.d.ts +4 -1
  27. package/dist/shared/@outfitter/tooling-0zjz8eg9.js +106 -0
  28. package/dist/shared/@outfitter/tooling-2vv5y3s4.js +145 -0
  29. package/dist/shared/@outfitter/{tooling-875svjnz.js → tooling-5xxctk9b.js} +2 -113
  30. package/dist/shared/@outfitter/tooling-5ynz680q.js +59 -0
  31. package/dist/shared/@outfitter/tooling-7437rmy6.js +39 -0
  32. package/dist/shared/@outfitter/tooling-8qcwr06t.d.ts +74 -0
  33. package/dist/shared/@outfitter/tooling-a59br34g.js +32 -0
  34. package/dist/shared/@outfitter/tooling-a6q3zh7t.js +86 -0
  35. package/dist/shared/@outfitter/tooling-ayps7c4x.js +58 -0
  36. package/dist/shared/@outfitter/{tooling-d363b88r.js → tooling-c8q6mj8z.js} +27 -148
  37. package/dist/shared/@outfitter/{tooling-wesswf21.d.ts → tooling-cb0b8wsx.d.ts} +9 -11
  38. package/dist/shared/@outfitter/tooling-f8q38e9z.d.ts +16 -0
  39. package/dist/shared/@outfitter/tooling-h5dnevjw.js +139 -0
  40. package/dist/shared/@outfitter/tooling-j8d1h2zd.d.ts +10 -0
  41. package/dist/shared/@outfitter/tooling-mq2xvz96.js +285 -0
  42. package/dist/shared/@outfitter/tooling-stgnc2zx.d.ts +85 -0
  43. package/dist/shared/@outfitter/tooling-tj9p41vj.d.ts +55 -0
  44. package/dist/shared/@outfitter/tooling-y43b117h.d.ts +13 -0
  45. package/lefthook.yml +5 -1
  46. package/package.json +10 -4
  47. package/registry/registry.json +5 -5
  48. package/dist/shared/@outfitter/tooling-6cxfdx0q.js +0 -187
  49. package/dist/shared/@outfitter/tooling-h04te11c.js +0 -231
  50. package/dist/shared/@outfitter/tooling-njw4z34x.d.ts +0 -140
@@ -1,187 +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].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,231 +0,0 @@
1
- // @bun
2
- // packages/tooling/src/cli/check-exports.ts
3
- import { resolve } from "path";
4
- function entryToSubpath(entry) {
5
- const stripped = entry.replace(/^src\//, "").replace(/\.[cm]?[jt]sx?$/, "");
6
- if (stripped === "index") {
7
- return ".";
8
- }
9
- if (stripped.endsWith("/index")) {
10
- return `./${stripped.slice(0, -"/index".length)}`;
11
- }
12
- return `./${stripped}`;
13
- }
14
- function compareExports(input) {
15
- const { name, actual, expected, path } = input;
16
- const actualKeys = new Set(Object.keys(actual));
17
- const expectedKeys = new Set(Object.keys(expected));
18
- const added = [];
19
- const removed = [];
20
- const changed = [];
21
- for (const key of expectedKeys) {
22
- if (!actualKeys.has(key)) {
23
- added.push(key);
24
- }
25
- }
26
- for (const key of actualKeys) {
27
- if (!expectedKeys.has(key)) {
28
- removed.push(key);
29
- }
30
- }
31
- for (const key of actualKeys) {
32
- if (expectedKeys.has(key)) {
33
- const actualValue = actual[key];
34
- const expectedValue = expected[key];
35
- if (JSON.stringify(actualValue) !== JSON.stringify(expectedValue)) {
36
- changed.push({ key, expected: expectedValue, actual: actualValue });
37
- }
38
- }
39
- }
40
- added.sort();
41
- removed.sort();
42
- changed.sort((a, b) => a.key.localeCompare(b.key));
43
- if (added.length === 0 && removed.length === 0 && changed.length === 0) {
44
- return { name, status: "ok" };
45
- }
46
- return {
47
- name,
48
- status: "drift",
49
- drift: {
50
- package: name,
51
- path: path ?? "",
52
- added,
53
- removed,
54
- changed
55
- }
56
- };
57
- }
58
- function matchesExclude(subpath, excludes) {
59
- return excludes.some((pattern) => new Bun.Glob(pattern).match(subpath));
60
- }
61
- var CLI_EXCLUSION_PATTERNS = [
62
- "**/cli.ts",
63
- "**/cli/index.ts",
64
- "**/bin.ts",
65
- "**/bin/index.ts"
66
- ];
67
- function isCliEntrypoint(entry) {
68
- return CLI_EXCLUSION_PATTERNS.some((pattern) => new Bun.Glob(pattern).match(entry));
69
- }
70
- function buildExportValue(entry) {
71
- const distPath = entry.replace(/^src\//, "").replace(/\.[cm]?[jt]sx?$/, "");
72
- return {
73
- import: {
74
- types: `./dist/${distPath}.d.ts`,
75
- default: `./dist/${distPath}.js`
76
- }
77
- };
78
- }
79
- function discoverEntries(packageRoot) {
80
- const glob = new Bun.Glob("src/**/*.ts");
81
- const entries = [];
82
- for (const match of glob.scanSync({ cwd: packageRoot, dot: false })) {
83
- if (match.includes("__tests__") || match.endsWith(".test.ts")) {
84
- continue;
85
- }
86
- entries.push(match);
87
- }
88
- return entries.toSorted();
89
- }
90
- function addConfigFileExports(expected, pkg) {
91
- const CONFIG_RE = /\.(json|jsonc|yml|yaml|toml)$/;
92
- const configFiles = (pkg.files ?? []).filter((file) => CONFIG_RE.test(file) && file !== "package.json");
93
- for (const file of configFiles) {
94
- expected[`./${file}`] = `./${file}`;
95
- let base = file.replace(CONFIG_RE, "");
96
- const match = base.match(/^(.+)\.preset(?:\.(.+))?$/);
97
- if (match?.[1]) {
98
- base = match[2] ? `${match[1]}-${match[2]}` : match[1];
99
- }
100
- if (base !== file) {
101
- expected[`./${base}`] = `./${file}`;
102
- }
103
- }
104
- }
105
- function computeExpectedExports(packageRoot, workspace, pkg) {
106
- const entries = discoverEntries(packageRoot);
107
- const exportsConfig = typeof workspace.config?.exports === "object" ? workspace.config.exports : undefined;
108
- const excludes = exportsConfig?.exclude ?? [];
109
- const customExports = exportsConfig?.customExports ?? {};
110
- const expected = {};
111
- const subpathEntries = new Map;
112
- for (const entry of entries) {
113
- if (isCliEntrypoint(entry))
114
- continue;
115
- const subpath = entryToSubpath(entry);
116
- if (matchesExclude(subpath, excludes))
117
- continue;
118
- const existing = subpathEntries.get(subpath);
119
- if (existing) {
120
- if (!existing.endsWith("/index.ts") && entry.endsWith("/index.ts")) {
121
- continue;
122
- }
123
- }
124
- subpathEntries.set(subpath, entry);
125
- }
126
- for (const [subpath, entry] of subpathEntries) {
127
- expected[subpath] = buildExportValue(entry);
128
- }
129
- for (const [key, value] of Object.entries(customExports)) {
130
- expected[`./${key.replace(/^\.\//, "")}`] = value;
131
- }
132
- addConfigFileExports(expected, pkg);
133
- expected["./package.json"] = "./package.json";
134
- return expected;
135
- }
136
- var COLORS = {
137
- reset: "\x1B[0m",
138
- red: "\x1B[31m",
139
- green: "\x1B[32m",
140
- yellow: "\x1B[33m",
141
- blue: "\x1B[34m",
142
- dim: "\x1B[2m"
143
- };
144
- function resolveJsonMode(options = {}) {
145
- return options.json ?? process.env["OUTFITTER_JSON"] === "1";
146
- }
147
- async function runCheckExports(options = {}) {
148
- const cwd = process.cwd();
149
- const configPath = resolve(cwd, "bunup.config.ts");
150
- let workspaces;
151
- try {
152
- const configModule = await import(configPath);
153
- const rawConfig = configModule.default;
154
- if (!Array.isArray(rawConfig)) {
155
- process.stderr.write(`bunup.config.ts must export a workspace array
156
- `);
157
- process.exitCode = 1;
158
- return;
159
- }
160
- workspaces = rawConfig;
161
- } catch {
162
- process.stderr.write(`Could not load bunup.config.ts from ${cwd}
163
- `);
164
- process.exitCode = 1;
165
- return;
166
- }
167
- const results = [];
168
- for (const workspace of workspaces) {
169
- const packageRoot = resolve(cwd, workspace.root);
170
- const pkgPath = resolve(packageRoot, "package.json");
171
- let pkg;
172
- try {
173
- pkg = await Bun.file(pkgPath).json();
174
- } catch {
175
- results.push({ name: workspace.name, status: "ok" });
176
- continue;
177
- }
178
- const actual = typeof pkg.exports === "object" && pkg.exports !== null ? pkg.exports : {};
179
- const expected = computeExpectedExports(packageRoot, workspace, pkg);
180
- results.push(compareExports({
181
- name: workspace.name,
182
- actual,
183
- expected,
184
- path: workspace.root
185
- }));
186
- }
187
- const checkResult = {
188
- ok: results.every((r) => r.status === "ok"),
189
- packages: results
190
- };
191
- if (resolveJsonMode(options)) {
192
- process.stdout.write(`${JSON.stringify(checkResult, null, 2)}
193
- `);
194
- } else {
195
- const drifted = results.filter((r) => r.status === "drift");
196
- if (drifted.length === 0) {
197
- process.stdout.write(`${COLORS.green}All ${results.length} packages have exports in sync.${COLORS.reset}
198
- `);
199
- } else {
200
- process.stderr.write(`${COLORS.red}Export drift detected in ${drifted.length} package(s):${COLORS.reset}
201
-
202
- `);
203
- for (const result of drifted) {
204
- const drift = result.drift;
205
- if (!drift)
206
- continue;
207
- process.stderr.write(` ${COLORS.yellow}${result.name}${COLORS.reset} ${COLORS.dim}(${drift.path})${COLORS.reset}
208
- `);
209
- for (const key of drift.added) {
210
- process.stderr.write(` ${COLORS.green}+ ${key}${COLORS.reset} ${COLORS.dim}(missing from package.json)${COLORS.reset}
211
- `);
212
- }
213
- for (const key of drift.removed) {
214
- process.stderr.write(` ${COLORS.red}- ${key}${COLORS.reset} ${COLORS.dim}(not in source)${COLORS.reset}
215
- `);
216
- }
217
- for (const entry of drift.changed) {
218
- process.stderr.write(` ${COLORS.yellow}~ ${entry.key}${COLORS.reset} ${COLORS.dim}(value mismatch)${COLORS.reset}
219
- `);
220
- }
221
- process.stderr.write(`
222
- `);
223
- }
224
- process.stderr.write(`Run ${COLORS.blue}bun run build${COLORS.reset} to regenerate exports.
225
- `);
226
- }
227
- }
228
- process.exitCode = checkResult.ok ? 0 : 1;
229
- }
230
-
231
- export { entryToSubpath, compareExports, resolveJsonMode, runCheckExports };
@@ -1,140 +0,0 @@
1
- import ts from "typescript";
2
- import { ZodType } from "zod";
3
- /** Coverage classification for a single declaration. */
4
- type CoverageLevel = "documented" | "partial" | "undocumented";
5
- /** Result for a single exported declaration. */
6
- interface DeclarationCoverage {
7
- readonly name: string;
8
- readonly kind: string;
9
- readonly level: CoverageLevel;
10
- readonly file: string;
11
- readonly line: number;
12
- }
13
- /** Coverage summary statistics. */
14
- interface CoverageSummary {
15
- readonly documented: number;
16
- readonly partial: number;
17
- readonly undocumented: number;
18
- readonly total: number;
19
- readonly percentage: number;
20
- }
21
- /** Per-package TSDoc coverage stats. */
22
- interface PackageCoverage {
23
- readonly name: string;
24
- readonly path: string;
25
- readonly declarations: readonly DeclarationCoverage[];
26
- readonly documented: number;
27
- readonly partial: number;
28
- readonly undocumented: number;
29
- readonly total: number;
30
- readonly percentage: number;
31
- }
32
- /** Aggregated result across all packages. */
33
- interface TsDocCheckResult {
34
- readonly ok: boolean;
35
- readonly packages: readonly PackageCoverage[];
36
- readonly summary: CoverageSummary;
37
- }
38
- /** Zod schema for {@link CoverageLevel}. */
39
- declare const coverageLevelSchema: ZodType<CoverageLevel>;
40
- /** Zod schema for {@link DeclarationCoverage}. */
41
- declare const declarationCoverageSchema: ZodType<DeclarationCoverage>;
42
- /** Zod schema for {@link CoverageSummary}. */
43
- declare const coverageSummarySchema: ZodType<CoverageSummary>;
44
- /** Zod schema for {@link PackageCoverage}. */
45
- declare const packageCoverageSchema: ZodType<PackageCoverage>;
46
- /** Zod schema for {@link TsDocCheckResult}. */
47
- declare const tsDocCheckResultSchema: ZodType<TsDocCheckResult>;
48
- /** Options for the check-tsdoc command. */
49
- interface CheckTsDocOptions {
50
- readonly strict?: boolean | undefined;
51
- readonly json?: boolean | undefined;
52
- readonly minCoverage?: number | undefined;
53
- readonly cwd?: string | undefined;
54
- readonly paths?: readonly string[] | undefined;
55
- }
56
- /**
57
- * Check whether a node is an exported declaration worth checking.
58
- *
59
- * Returns true for function, interface, type alias, class, enum, and variable
60
- * declarations that carry the `export` keyword. Re-exports (`{ ... } from`)
61
- * and `*` are excluded since TSDoc belongs at the definition site.
62
- */
63
- declare function isExportedDeclaration(node: ts.Node): boolean;
64
- /**
65
- * Extract the name of a declaration node.
66
- *
67
- * For variable statements, returns the name of the first variable declarator.
68
- * Returns `undefined` for anonymous declarations (e.g., `function() {}`).
69
- */
70
- declare function getDeclarationName(node: ts.Node): string | undefined;
71
- /**
72
- * Determine the kind label for a declaration node.
73
- *
74
- * Maps AST node types to human-readable kind strings used in coverage reports.
75
- */
76
- declare function getDeclarationKind(node: ts.Node): string;
77
- /**
78
- * Classify a declaration's TSDoc coverage level.
79
- *
80
- * - `"documented"` -- has a JSDoc comment with a description. For interfaces
81
- * and classes, all members must also have JSDoc comments.
82
- * - `"partial"` -- the declaration has a JSDoc comment but some members
83
- * (in interfaces/classes) lack documentation.
84
- * - `"undocumented"` -- no JSDoc comment at all.
85
- */
86
- declare function classifyDeclaration(node: ts.Node, sourceFile: ts.SourceFile): CoverageLevel;
87
- /**
88
- * Analyze all exported declarations in a source file for TSDoc coverage.
89
- *
90
- * Walks top-level statements, filters to exported declarations, and
91
- * classifies each for documentation coverage.
92
- */
93
- declare function analyzeSourceFile(sourceFile: ts.SourceFile): DeclarationCoverage[];
94
- /**
95
- * Calculate aggregate coverage statistics from declaration results.
96
- *
97
- * Partial documentation counts as half coverage in the percentage calculation.
98
- * An empty array returns 100% (no declarations to check).
99
- */
100
- declare function calculateCoverage(declarations: readonly DeclarationCoverage[]): {
101
- documented: number;
102
- partial: number;
103
- undocumented: number;
104
- total: number;
105
- percentage: number;
106
- };
107
- /** Resolve whether JSON output mode is active. */
108
- declare function resolveJsonMode(options?: CheckTsDocOptions): boolean;
109
- /**
110
- * Analyze TSDoc coverage across workspace packages.
111
- *
112
- * Pure function that discovers packages, analyzes TSDoc coverage on exported
113
- * declarations, and returns the aggregated result. Does not print output or
114
- * call `process.exit()`.
115
- *
116
- * @param options - Analysis options (paths, strict mode, coverage threshold)
117
- * @returns Aggregated coverage result across all packages, or `null` if no packages found
118
- */
119
- declare function analyzeCheckTsdoc(options?: CheckTsDocOptions): TsDocCheckResult | null;
120
- /**
121
- * Print a TSDoc coverage result in human-readable format.
122
- *
123
- * Renders a bar chart per package with summary statistics. Writes to stdout/stderr.
124
- *
125
- * @param result - The coverage result to print
126
- * @param options - Display options (strict mode, coverage threshold for warning)
127
- */
128
- declare function printCheckTsdocHuman(result: TsDocCheckResult, options?: {
129
- strict?: boolean | undefined;
130
- minCoverage?: number | undefined;
131
- }): void;
132
- /**
133
- * Run check-tsdoc across workspace packages.
134
- *
135
- * Discovers packages with `src/index.ts` entry points, analyzes TSDoc
136
- * coverage on exported declarations, and reports per-package statistics.
137
- * Calls `process.exit()` on completion.
138
- */
139
- declare function runCheckTsdoc(options?: CheckTsDocOptions): Promise<void>;
140
- export { CoverageLevel, DeclarationCoverage, CoverageSummary, PackageCoverage, TsDocCheckResult, coverageLevelSchema, declarationCoverageSchema, coverageSummarySchema, packageCoverageSchema, tsDocCheckResultSchema, CheckTsDocOptions, isExportedDeclaration, getDeclarationName, getDeclarationKind, classifyDeclaration, analyzeSourceFile, calculateCoverage, resolveJsonMode, analyzeCheckTsdoc, printCheckTsdocHuman, runCheckTsdoc };