rcf-lite 0.28.0 → 0.28.2
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/CHANGELOG.md +115 -0
- package/README.md +9 -0
- package/fixtures/canary-manifest.json +9 -9
- package/package.json +1 -1
- package/rcf/code-nodes/cn-600.json +2 -1
- package/rcf/code-nodes/cn-602.json +4 -2
- package/rcf/code-nodes/cn-605.json +2 -1
- package/rcf/fbs/fbs-181.json +4 -2
- package/rcf/fbs/fbs-182.json +2 -1
- package/rcf/tacs/tac-4103-feedback-redact.json +3 -2
- package/rcf/tacs/tac-4106-feedback-destination.json +3 -2
- package/rcf/test-suites/ts-188.json +18 -2
- package/rcf/test-suites/ts-189.json +24 -2
- package/rcf/test-suites/ts-191.json +19 -5
- package/rcf/user-stories/us-15601.json +19 -1
- package/rcf/user-stories/us-15701.json +4 -4
- package/rcf/user-stories/us-15801.json +10 -1
- package/releases/releases.yaml +21 -1
- package/src/browser-verify/manifest-writer.js +9 -5
- package/src/cli/browser-verify.js +9 -1
- package/src/cli/feedback.js +201 -24
- package/src/cli/intake.js +25 -4
- package/src/cli/preflight.js +24 -3
- package/src/cli/review.js +9 -1
- package/src/cli/ui-baseline.js +14 -1
- package/src/core/store/index.js +5 -0
- package/src/core/store/validate-composed-record.js +95 -0
- package/src/feedback/destination.js +98 -4
- package/src/feedback/gh.js +27 -1
- package/src/feedback/redact-allowlist.json +7 -0
- package/src/feedback/redact.js +75 -6
- package/src/feedback/render.js +34 -12
- package/src/intake/manifest-writer.js +6 -3
- package/src/intake/orchestrator.js +44 -7
- package/src/preflight/manifest-writer.js +11 -11
- package/src/req-baseline/sweep.js +34 -5
- package/src/ui-baseline/manifest-writer.js +11 -10
- package/src/view/doc-renderers/helpers.js +37 -0
- package/src/view/doc-renderers/tad.js +67 -6
- package/src/view/style.css +5 -0
|
@@ -77,6 +77,43 @@ export function fieldList(label, items) {
|
|
|
77
77
|
return `<section class="field-list"><h4>${escapeHtml(label)}</h4><ul>${li}</ul></section>`;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* 0.28.2 (issue #235): render an array-of-object field as a HTML
|
|
82
|
+
* table with the schema-known columns. Empty columns are suppressed so
|
|
83
|
+
* schema-optional fields do not surface as blank columns. Every cell
|
|
84
|
+
* is escaped. Used by the TAD renderer for the three structured
|
|
85
|
+
* fields the TAD schema names (dataStores, coreEntities,
|
|
86
|
+
* externalSystems) so a review-surface reader sees a legible table
|
|
87
|
+
* instead of a single-line `JSON.stringify` dump.
|
|
88
|
+
*
|
|
89
|
+
* @param {string} label section heading
|
|
90
|
+
* @param {object[]} rows array of row objects (dropped when empty)
|
|
91
|
+
* @param {Array<{ key: string, label?: string }>} columns
|
|
92
|
+
* @returns {string}
|
|
93
|
+
*/
|
|
94
|
+
export function fieldObjectTable(label, rows, columns) {
|
|
95
|
+
if (!Array.isArray(rows) || rows.length === 0) return '';
|
|
96
|
+
if (!Array.isArray(columns) || columns.length === 0) return '';
|
|
97
|
+
// Drop columns that are empty across every row so a schema-optional
|
|
98
|
+
// field (`purpose`, `description`, `protocol`) does not surface as
|
|
99
|
+
// a blank column.
|
|
100
|
+
const usedColumns = columns.filter((col) => rows.some((r) => {
|
|
101
|
+
const v = r?.[col.key];
|
|
102
|
+
return v !== undefined && v !== null && String(v).length > 0;
|
|
103
|
+
}));
|
|
104
|
+
if (usedColumns.length === 0) return '';
|
|
105
|
+
const thead = usedColumns.map((c) => `<th>${escapeHtml(c.label ?? c.key)}</th>`).join('');
|
|
106
|
+
const tbody = rows.map((r) => {
|
|
107
|
+
const cells = usedColumns.map((c) => {
|
|
108
|
+
const v = r?.[c.key];
|
|
109
|
+
const text = v === undefined || v === null ? '' : String(v);
|
|
110
|
+
return `<td>${escapeHtml(text)}</td>`;
|
|
111
|
+
}).join('');
|
|
112
|
+
return `<tr>${cells}</tr>`;
|
|
113
|
+
}).join('');
|
|
114
|
+
return `<section class="field-list"><h4>${escapeHtml(label)}</h4><table class="field-table"><thead><tr>${thead}</tr></thead><tbody>${tbody}</tbody></table></section>`;
|
|
115
|
+
}
|
|
116
|
+
|
|
80
117
|
/**
|
|
81
118
|
* Render the "Show raw JSON" disclosure block for a document.
|
|
82
119
|
*
|
|
@@ -9,10 +9,34 @@ import {
|
|
|
9
9
|
docLinkList,
|
|
10
10
|
escapeHtml,
|
|
11
11
|
fieldList,
|
|
12
|
+
fieldObjectTable,
|
|
12
13
|
fieldPara,
|
|
13
14
|
rawJsonDisclosure,
|
|
14
15
|
} from './helpers.js';
|
|
15
16
|
|
|
17
|
+
// 0.28.2 (issue #235): structured fields the TAD schema explicitly
|
|
18
|
+
// types as arrays of objects. Each entry maps a field-key to the
|
|
19
|
+
// schema-documented column layout so `renderOptionalSections` can
|
|
20
|
+
// pick a table renderer over the raw-JSON dump the pre-fix code
|
|
21
|
+
// emitted. Columns follow @stravica-ai/rcf-schemas@0.6.3
|
|
22
|
+
// schemas/tad.schema.json.
|
|
23
|
+
const TAD_STRUCTURED_FIELDS = {
|
|
24
|
+
dataStores: [
|
|
25
|
+
{ key: 'name', label: 'Name' },
|
|
26
|
+
{ key: 'kind', label: 'Kind' },
|
|
27
|
+
{ key: 'purpose', label: 'Purpose' },
|
|
28
|
+
],
|
|
29
|
+
coreEntities: [
|
|
30
|
+
{ key: 'name', label: 'Name' },
|
|
31
|
+
{ key: 'description', label: 'Description' },
|
|
32
|
+
],
|
|
33
|
+
externalSystems: [
|
|
34
|
+
{ key: 'name', label: 'Name' },
|
|
35
|
+
{ key: 'purpose', label: 'Purpose' },
|
|
36
|
+
{ key: 'protocol', label: 'Protocol' },
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
|
|
16
40
|
/**
|
|
17
41
|
* @param {object} tad
|
|
18
42
|
* @param {object} ctx
|
|
@@ -63,12 +87,49 @@ function renderOptionalSections(tad) {
|
|
|
63
87
|
for (const [key, label] of Object.entries(named)) {
|
|
64
88
|
const section = tad[key];
|
|
65
89
|
if (!section || typeof section !== 'object') continue;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
90
|
+
// 0.28.2 (issue #235): pull the schema-known structured fields
|
|
91
|
+
// (dataStores, coreEntities, externalSystems) out of the generic
|
|
92
|
+
// dl loop and render them as tables. The remaining scalar and
|
|
93
|
+
// array-of-string fields keep their dl treatment.
|
|
94
|
+
const structuredBlocks = [];
|
|
95
|
+
const dlEntries = [];
|
|
96
|
+
for (const [k, v] of Object.entries(section)) {
|
|
97
|
+
if (TAD_STRUCTURED_FIELDS[k] && Array.isArray(v) && v.length > 0 && v.every((x) => x && typeof x === 'object')) {
|
|
98
|
+
const table = fieldObjectTable(prettyStructuredLabel(k), v, TAD_STRUCTURED_FIELDS[k]);
|
|
99
|
+
if (table) structuredBlocks.push(table);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (typeof v === 'string') {
|
|
103
|
+
dlEntries.push(`<dt>${escapeHtml(k)}</dt><dd>${escapeHtml(v)}</dd>`);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (Array.isArray(v)) {
|
|
107
|
+
// Array-of-string keeps the existing inline shape. An
|
|
108
|
+
// unknown array-of-object surface falls through to a nested
|
|
109
|
+
// disclosure so it stays legible even when the schema grows
|
|
110
|
+
// a new field before this renderer knows about it.
|
|
111
|
+
if (v.every((x) => typeof x !== 'object' || x === null)) {
|
|
112
|
+
dlEntries.push(`<dt>${escapeHtml(k)}</dt><dd>${v.map((x) => `<code>${escapeHtml(typeof x === 'object' ? JSON.stringify(x) : x)}</code>`).join(', ')}</dd>`);
|
|
113
|
+
} else {
|
|
114
|
+
const items = v.map((x) => `<li><pre>${escapeHtml(JSON.stringify(x, null, 2))}</pre></li>`).join('');
|
|
115
|
+
dlEntries.push(`<dt>${escapeHtml(k)}</dt><dd><ul>${items}</ul></dd>`);
|
|
116
|
+
}
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
dlEntries.push(`<dt>${escapeHtml(k)}</dt><dd><pre>${escapeHtml(JSON.stringify(v, null, 2))}</pre></dd>`);
|
|
120
|
+
}
|
|
121
|
+
const dl = dlEntries.length > 0 ? `<dl>${dlEntries.join('\n')}</dl>` : '';
|
|
122
|
+
const structured = structuredBlocks.join('\n');
|
|
123
|
+
out.push(`<section class="field-list"><h4>${escapeHtml(label)}</h4>${dl}${structured}</section>`);
|
|
72
124
|
}
|
|
73
125
|
return out.join('\n');
|
|
74
126
|
}
|
|
127
|
+
|
|
128
|
+
function prettyStructuredLabel(key) {
|
|
129
|
+
const map = {
|
|
130
|
+
dataStores: 'Data stores',
|
|
131
|
+
coreEntities: 'Core entities',
|
|
132
|
+
externalSystems: 'External systems',
|
|
133
|
+
};
|
|
134
|
+
return map[key] ?? key;
|
|
135
|
+
}
|
package/src/view/style.css
CHANGED
|
@@ -294,6 +294,11 @@ article.doc h5 { margin: 0.6rem 0 0.3rem; font-size: 0.925rem; font-weight: 600;
|
|
|
294
294
|
.field-list ul li { margin: 0.2rem 0; }
|
|
295
295
|
.field-list dl dt { font-weight: 600; margin-top: 0.5rem; color: var(--colour-heading); }
|
|
296
296
|
.field-list dl dd { margin-left: 0; margin-bottom: 0.35rem; }
|
|
297
|
+
/* 0.28.2 (issue #235): structured TAD fields render as a table. */
|
|
298
|
+
.field-list table.field-table { border-collapse: collapse; width: 100%; margin: 0.35rem 0 0.85rem; font-size: 0.95em; }
|
|
299
|
+
.field-list table.field-table th, .field-list table.field-table td { text-align: left; padding: 0.35rem 0.55rem; border-bottom: 1px solid var(--colour-rule, rgba(0,0,0,0.12)); vertical-align: top; }
|
|
300
|
+
.field-list table.field-table th { font-weight: 600; color: var(--colour-heading); background: var(--colour-tint, rgba(0,0,0,0.03)); }
|
|
301
|
+
.field-list table.field-table tr:last-child td { border-bottom: 0; }
|
|
297
302
|
|
|
298
303
|
/* --------------------------------------------------------------------
|
|
299
304
|
* Acceptance criteria list (inside a US)
|