dotmd-cli 0.31.0 → 0.31.1
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/export.mjs +4 -4
- package/src/git.mjs +25 -0
- package/src/graph.mjs +2 -0
- package/src/render.mjs +4 -4
- package/src/stats.mjs +2 -2
- package/src/validate.mjs +2 -2
package/package.json
CHANGED
package/src/export.mjs
CHANGED
|
@@ -151,8 +151,8 @@ function exportMarkdown(docs, config) {
|
|
|
151
151
|
lines.push(`### ${doc.title}`);
|
|
152
152
|
const meta = [`Status: ${doc.status}`];
|
|
153
153
|
if (doc.updated) meta.push(`Updated: ${doc.updated}`);
|
|
154
|
-
if (doc.
|
|
155
|
-
if (doc.
|
|
154
|
+
if (doc.modules?.length) meta.push(`Module: ${doc.modules.join(', ')}`);
|
|
155
|
+
if (doc.surfaces?.length) meta.push(`Surface: ${doc.surfaces.join(', ')}`);
|
|
156
156
|
if (doc.owner) meta.push(`Owner: ${doc.owner}`);
|
|
157
157
|
lines.push(`> ${meta.join(' | ')}`, '');
|
|
158
158
|
if (doc.body.trim()) lines.push(doc.body.trim());
|
|
@@ -292,8 +292,8 @@ function buildDocPage(doc) {
|
|
|
292
292
|
let meta = `<table class="meta">`;
|
|
293
293
|
meta += `<tr><td>Status</td><td><span class="badge ${badgeClass}">${doc.status ?? 'unknown'}</span></td></tr>`;
|
|
294
294
|
if (doc.updated) meta += `<tr><td>Updated</td><td>${escHtml(doc.updated)}</td></tr>`;
|
|
295
|
-
if (doc.
|
|
296
|
-
if (doc.
|
|
295
|
+
if (doc.modules?.length) meta += `<tr><td>Module</td><td>${escHtml(doc.modules.join(', '))}</td></tr>`;
|
|
296
|
+
if (doc.surfaces?.length) meta += `<tr><td>Surface</td><td>${escHtml(doc.surfaces.join(', '))}</td></tr>`;
|
|
297
297
|
if (doc.owner) meta += `<tr><td>Owner</td><td>${escHtml(doc.owner)}</td></tr>`;
|
|
298
298
|
meta += `<tr><td>Path</td><td><code>${escHtml(doc.path)}</code></td></tr>`;
|
|
299
299
|
meta += `</table>`;
|
package/src/git.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { renameSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
2
4
|
|
|
3
5
|
let gitChecked = false;
|
|
4
6
|
function ensureGit() {
|
|
@@ -49,6 +51,20 @@ export function getGitLastModifiedBatch(repoRoot) {
|
|
|
49
51
|
|
|
50
52
|
export function gitMv(source, target, repoRoot) {
|
|
51
53
|
ensureGit();
|
|
54
|
+
// Source is untracked (scaffolded this session, never committed; or repoRoot
|
|
55
|
+
// is not a git repo at all): a plain rename is the only correct move. `git mv`
|
|
56
|
+
// would error with `fatal: not under version control` and the user can't act
|
|
57
|
+
// on that — the file is genuinely a doc, just not yet staged.
|
|
58
|
+
if (!isTracked(source, repoRoot)) {
|
|
59
|
+
const absSource = path.isAbsolute(source) ? source : path.join(repoRoot, source);
|
|
60
|
+
const absTarget = path.isAbsolute(target) ? target : path.join(repoRoot, target);
|
|
61
|
+
try {
|
|
62
|
+
renameSync(absSource, absTarget);
|
|
63
|
+
return { status: 0, stderr: '' };
|
|
64
|
+
} catch (err) {
|
|
65
|
+
return { status: 1, stderr: err.message };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
52
68
|
const result = spawnSync('git', ['mv', source, target], {
|
|
53
69
|
cwd: repoRoot,
|
|
54
70
|
encoding: 'utf8',
|
|
@@ -56,6 +72,15 @@ export function gitMv(source, target, repoRoot) {
|
|
|
56
72
|
return { status: result.status, stderr: result.stderr };
|
|
57
73
|
}
|
|
58
74
|
|
|
75
|
+
function isTracked(source, repoRoot) {
|
|
76
|
+
const relSource = path.isAbsolute(source) ? path.relative(repoRoot, source) : source;
|
|
77
|
+
const result = spawnSync('git', ['ls-files', '--error-unmatch', '--', relSource], {
|
|
78
|
+
cwd: repoRoot,
|
|
79
|
+
encoding: 'utf8',
|
|
80
|
+
});
|
|
81
|
+
return result.status === 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
59
84
|
export function gitDiffSince(relPath, sinceDate, repoRoot, opts = {}) {
|
|
60
85
|
ensureGit();
|
|
61
86
|
// Find the last commit at or before sinceDate
|
package/src/graph.mjs
CHANGED
|
@@ -43,7 +43,9 @@ export function buildGraph(index, config, filters = {}) {
|
|
|
43
43
|
title: d.title,
|
|
44
44
|
status: d.status,
|
|
45
45
|
module: d.module,
|
|
46
|
+
modules: d.modules,
|
|
46
47
|
surface: d.surface,
|
|
48
|
+
surfaces: d.surfaces,
|
|
47
49
|
edgeCount: 0,
|
|
48
50
|
}));
|
|
49
51
|
const nodeMap = new Map(nodes.map(n => [n.id, n]));
|
package/src/render.mjs
CHANGED
|
@@ -379,10 +379,10 @@ export function renderCoverage(index, config) {
|
|
|
379
379
|
export function buildCoverage(index, config) {
|
|
380
380
|
const scope = [...new Set(index.docs.map(d => d.status).filter(s => s && !config.lifecycle.terminalStatuses.has(s)))];
|
|
381
381
|
const scoped = index.docs.filter(doc => doc.status && !config.lifecycle.terminalStatuses.has(doc.status));
|
|
382
|
-
const missingSurface = scoped.filter(doc => !doc.
|
|
383
|
-
const missingModule = scoped.filter(doc => !doc.
|
|
384
|
-
const modulePlatform = scoped.filter(doc => doc.
|
|
385
|
-
const moduleNone = scoped.filter(doc => doc.
|
|
382
|
+
const missingSurface = scoped.filter(doc => !doc.surfaces?.length);
|
|
383
|
+
const missingModule = scoped.filter(doc => !doc.modules?.length);
|
|
384
|
+
const modulePlatform = scoped.filter(doc => doc.modules?.includes('platform'));
|
|
385
|
+
const moduleNone = scoped.filter(doc => doc.modules?.includes('none'));
|
|
386
386
|
const auditLevelNone = scoped.filter(doc => doc.auditLevel === 'none');
|
|
387
387
|
const audited = scoped.filter(doc => ['pass1', 'pass2', 'deep'].includes(doc.auditLevel));
|
|
388
388
|
|
package/src/stats.mjs
CHANGED
|
@@ -64,8 +64,8 @@ export function buildStats(index, config) {
|
|
|
64
64
|
completeness: {
|
|
65
65
|
scoped: scoped.length,
|
|
66
66
|
hasOwner: scoped.filter(d => d.owner).length,
|
|
67
|
-
hasSurface: scoped.filter(d => d.
|
|
68
|
-
hasModule: scoped.filter(d => d.
|
|
67
|
+
hasSurface: scoped.filter(d => d.surfaces?.length).length,
|
|
68
|
+
hasModule: scoped.filter(d => d.modules?.length).length,
|
|
69
69
|
hasNextStep: scoped.filter(d => d.hasNextStep).length,
|
|
70
70
|
},
|
|
71
71
|
checklists: {
|
package/src/validate.mjs
CHANGED
|
@@ -102,8 +102,8 @@ export function validateDoc(doc, frontmatter, headingTitle, config) {
|
|
|
102
102
|
doc.errors.push({ path: doc.path, level: 'error', message: '`modules` must be a YAML list when present.' });
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
if (config.moduleRequiredStatuses.has(doc.status) && !doc.
|
|
106
|
-
doc.errors.push({ path: doc.path, level: 'error', message: '`module` is required for active/ready/planned/blocked docs; use a real module, `platform`, or `none`.' });
|
|
105
|
+
if (config.moduleRequiredStatuses.has(doc.status) && !doc.modules?.length) {
|
|
106
|
+
doc.errors.push({ path: doc.path, level: 'error', message: '`module` is required for active/ready/planned/blocked docs; use a real module, `platform`, or `none`. Accepts singular `module:` or plural `modules:` list.' });
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
if (config.validSurfaces) {
|