dotmd-cli 0.39.5 → 0.39.6
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/package.json +1 -1
- package/src/index.mjs +13 -0
- package/src/stats.mjs +39 -9
package/package.json
CHANGED
package/src/index.mjs
CHANGED
|
@@ -74,6 +74,18 @@ export function buildIndex(config, opts = {}) {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
// Per-type counts (F6): same input docs, keyed by `type` first so callers
|
|
78
|
+
// can distinguish `plan/partial` (work shipped + tail deferred) from
|
|
79
|
+
// `doc/partial` (incomplete reference material). Untyped docs (pre-0.30
|
|
80
|
+
// corpora) land under `unknown` rather than getting dropped silently.
|
|
81
|
+
const countsByType = {};
|
|
82
|
+
for (const doc of transformedDocs) {
|
|
83
|
+
if (!doc.status) continue;
|
|
84
|
+
const type = doc.type || 'unknown';
|
|
85
|
+
if (!countsByType[type]) countsByType[type] = {};
|
|
86
|
+
countsByType[type][doc.status] = (countsByType[type][doc.status] ?? 0) + 1;
|
|
87
|
+
}
|
|
88
|
+
|
|
77
89
|
if (!fast) {
|
|
78
90
|
if (config.indexPath) {
|
|
79
91
|
const indexCheck = checkIndex(transformedDocs, config);
|
|
@@ -95,6 +107,7 @@ export function buildIndex(config, opts = {}) {
|
|
|
95
107
|
generatedAt: new Date().toISOString(),
|
|
96
108
|
docs: transformedDocs,
|
|
97
109
|
countsByStatus,
|
|
110
|
+
countsByType,
|
|
98
111
|
warnings,
|
|
99
112
|
errors,
|
|
100
113
|
};
|
package/src/stats.mjs
CHANGED
|
@@ -46,6 +46,7 @@ export function buildStats(index, config) {
|
|
|
46
46
|
generatedAt: new Date().toISOString(),
|
|
47
47
|
totalDocs: docs.length,
|
|
48
48
|
countsByStatus: index.countsByStatus,
|
|
49
|
+
countsByType: index.countsByType ?? {},
|
|
49
50
|
health: {
|
|
50
51
|
staleCount,
|
|
51
52
|
stalePct: pct(staleCount, nonArchived.length),
|
|
@@ -97,16 +98,45 @@ function _renderStats(stats, config) {
|
|
|
97
98
|
lines.push(bold(`Stats`) + dim(` — ${stats.totalDocs} docs`));
|
|
98
99
|
lines.push('');
|
|
99
100
|
|
|
100
|
-
// Status
|
|
101
|
+
// Status. With F6, render one line per type when 2+ types have docs so
|
|
102
|
+
// `plan/partial` and `doc/partial` (semantically distinct under per-type
|
|
103
|
+
// taxonomies) don't collapse into one number. Single-type corpora keep the
|
|
104
|
+
// existing flat line — no needless `Plans:` header on a plans-only repo.
|
|
101
105
|
lines.push(bold('Status'));
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
const typesWithDocs = Object.entries(stats.countsByType ?? {})
|
|
107
|
+
.filter(([, statusMap]) => Object.values(statusMap).some(n => n > 0));
|
|
108
|
+
if (typesWithDocs.length > 1) {
|
|
109
|
+
// Type order: respect config.validTypes declaration order; unknown last.
|
|
110
|
+
const typeOrder = [...(config.validTypes ?? [])];
|
|
111
|
+
const sortedTypes = typesWithDocs.sort(([a], [b]) => {
|
|
112
|
+
const ai = typeOrder.indexOf(a);
|
|
113
|
+
const bi = typeOrder.indexOf(b);
|
|
114
|
+
if (ai === -1 && bi === -1) return a.localeCompare(b);
|
|
115
|
+
if (ai === -1) return 1;
|
|
116
|
+
if (bi === -1) return -1;
|
|
117
|
+
return ai - bi;
|
|
118
|
+
});
|
|
119
|
+
const labelFor = (t) => t === 'unknown' ? 'Untyped' : (t.charAt(0).toUpperCase() + t.slice(1) + 's');
|
|
120
|
+
for (const [type, statusMap] of sortedTypes) {
|
|
121
|
+
const statusesForType = [
|
|
122
|
+
...config.statusOrder.filter(s => statusMap[s]),
|
|
123
|
+
...Object.keys(statusMap).filter(s => !config.statusOrder.includes(s)).sort(),
|
|
124
|
+
];
|
|
125
|
+
const parts = statusesForType
|
|
126
|
+
.filter(s => statusMap[s])
|
|
127
|
+
.map(s => `${s}: ${statusMap[s]}`);
|
|
128
|
+
lines.push(` ${dim(labelFor(type) + ':')} ${parts.join(' ')}`);
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
const allStatuses = [
|
|
132
|
+
...config.statusOrder.filter(s => stats.countsByStatus[s]),
|
|
133
|
+
...Object.keys(stats.countsByStatus).filter(s => !config.statusOrder.includes(s)).sort(),
|
|
134
|
+
];
|
|
135
|
+
const statusParts = allStatuses
|
|
136
|
+
.filter(s => stats.countsByStatus[s])
|
|
137
|
+
.map(s => `${s}: ${stats.countsByStatus[s]}`);
|
|
138
|
+
lines.push(' ' + statusParts.join(' '));
|
|
139
|
+
}
|
|
110
140
|
lines.push('');
|
|
111
141
|
|
|
112
142
|
// Health
|