@grove-dev/core 0.14.0 → 0.15.0

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.
@@ -0,0 +1,131 @@
1
+ /**
2
+ * The record normalizer: the one place that turns the three record
3
+ * layers into the record every output is built from.
4
+ *
5
+ * 1. Human source — `paths.recordsDir/<slug>.yml`, patched by
6
+ * `paths.overrides`.
7
+ * 2. Generated cache — `paths.githubCache/<slug>.json` (GitHub
8
+ * metadata and health, written by
9
+ * `grove sync github`), with a legacy inline
10
+ * `github` / `health` block and `paths.health`
11
+ * as fallbacks. Health from a stale sync resolves
12
+ * as `status: unknown` (`sync.github.maxAgeDays`).
13
+ * 3. Decisions — `paths.decisions`, which has the final say on
14
+ * visibility.
15
+ *
16
+ * `generate()` (browse, collections, SEO, sitemap, llms), `grove check`,
17
+ * `grove cleanup` and `grove readme generate` all read records through
18
+ * {@link loadNormalizedRecords}, so they cannot disagree about a
19
+ * record's fields or whether it is visible.
20
+ */
21
+ import { type GithubCache, type GithubFieldSource } from './github-cache.js';
22
+ import { type DecisionVisibility, type GroveConfig, type Resource } from './schema.js';
23
+ /** Where a normalized record's `health` block came from. */
24
+ export type RecordHealthSource =
25
+ /** `paths.githubCache/<slug>.json`. */
26
+ 'cache'
27
+ /** A legacy `health` block written inline on the record. */
28
+ | 'inline'
29
+ /** A `paths.overrides` patch. */
30
+ | 'override'
31
+ /** The record's entry in `paths.health`. */
32
+ | 'file'
33
+ /** Fabricated as "unknown" so a decision has a block to carry its visibility. */
34
+ | 'decision' | 'none';
35
+ /** A problem found while normalizing one record file. */
36
+ export interface RecordIssue {
37
+ code: 'schema_error' | 'zod_error' | 'github_cache_mismatch';
38
+ severity: 'error' | 'warning';
39
+ /** Record slug (the file name without its extension). */
40
+ slug: string;
41
+ /** Record file, relative to `cwd`. */
42
+ file: string;
43
+ /** Human-readable message, already prefixed with the slug. */
44
+ message: string;
45
+ }
46
+ export interface NormalizedRecord {
47
+ /** Canonical slug: always the file name without its extension. */
48
+ slug: string;
49
+ /** Record file, relative to `cwd`. */
50
+ file: string;
51
+ /**
52
+ * The record after every layer: source, GitHub cache (or legacy
53
+ * inline copy), overrides, `paths.health` and decisions. This is
54
+ * what the build serializes and every output renders.
55
+ */
56
+ record: Resource;
57
+ /**
58
+ * The record before `paths.health` and decisions are applied:
59
+ * source + GitHub cache + overrides, schema-parsed, slug from the
60
+ * file name. `grove check` compares this against `paths.health`.
61
+ */
62
+ base: Resource;
63
+ /** Effective visibility: decision, then health, then the record's own field. */
64
+ visibility: DecisionVisibility;
65
+ /** The `slug` value written in the file, which the file name overrides. */
66
+ declaredSlug: unknown;
67
+ provenance: {
68
+ github: GithubFieldSource;
69
+ health: RecordHealthSource;
70
+ /** True when `paths.decisions` has an entry for this record. */
71
+ decision: boolean;
72
+ /** True when `paths.overrides` has a patch for this record. */
73
+ override: boolean;
74
+ };
75
+ }
76
+ /** One record file in discovery order, whether or not it normalized. */
77
+ export interface RecordEntry {
78
+ slug: string;
79
+ file: string;
80
+ /** Problems with this file; an `error` means `record` is absent. */
81
+ issues: RecordIssue[];
82
+ /**
83
+ * True when the record's cached health came from a stale sync and
84
+ * resolved as `status: unknown` (see `githubSyncFreshness`).
85
+ */
86
+ syncStale: boolean;
87
+ /** Absent when the file failed to parse or validate. */
88
+ record?: NormalizedRecord;
89
+ }
90
+ export interface NormalizedRecords {
91
+ /** Records that normalized, sorted by file name. */
92
+ records: NormalizedRecord[];
93
+ /** Every record file, sorted by file name, with its issues. */
94
+ entries: RecordEntry[];
95
+ /** All issues from `entries`, flattened in the same order. */
96
+ issues: RecordIssue[];
97
+ /** The GitHub sync cache the records were resolved against. */
98
+ githubCache: GithubCache;
99
+ }
100
+ /**
101
+ * Apply a `paths.decisions` visibility to a record. For project records
102
+ * the decision overwrites `health.visibility`; a project with no health
103
+ * block gets a fabricated "unknown" one from {@link classifyHealth},
104
+ * because list and index payloads read visibility from `health`. For
105
+ * resource-hub and ecosystem-map records (no `health` block) it sets the
106
+ * top-level `visibility`.
107
+ */
108
+ export declare function applyDecisionVisibility(record: Resource, visibility: DecisionVisibility | undefined): Resource;
109
+ /**
110
+ * Discover, parse and merge every record under `config.paths.recordsDir`.
111
+ *
112
+ * Per record, lowest to highest precedence:
113
+ *
114
+ * 1. the record file (`paths.recordsDir/<slug>.yml`)
115
+ * 2. the GitHub sync cache, which supplies `github` / `health` over a
116
+ * legacy inline copy ({@link resolveRecordGithub})
117
+ * 3. the `paths.overrides` patch (shallow, top-level fields)
118
+ * 4. schema parse (`recordsFileSchema`); the slug is the file name
119
+ * 5. the `paths.health` entry, for a project record nothing above
120
+ * gave a health block
121
+ * 6. the `paths.decisions` visibility
122
+ *
123
+ * Effective visibility is then decision > health > the record's own
124
+ * `visibility` field ({@link recordVisibility}).
125
+ *
126
+ * Never throws for a bad record: a file that cannot be parsed or fails
127
+ * the schema is reported in `issues` and left out of `records`. Missing
128
+ * or invalid side files are treated as empty; `grove check` reports them.
129
+ */
130
+ export declare function loadNormalizedRecords(config: GroveConfig, cwd?: string): Promise<NormalizedRecords>;
131
+ //# sourceMappingURL=normalize-records.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-records.d.ts","sourceRoot":"","sources":["../src/normalize-records.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EAIvB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAEL,KAAK,kBAAkB,EAEvB,KAAK,WAAW,EAIhB,KAAK,QAAQ,EAMd,MAAM,aAAa,CAAC;AAErB,4DAA4D;AAC5D,MAAM,MAAM,kBAAkB;AAC5B,uCAAuC;AACrC,OAAO;AACT,4DAA4D;GAC1D,QAAQ;AACV,iCAAiC;GAC/B,UAAU;AACZ,4CAA4C;GAC1C,MAAM;AACR,iFAAiF;GAC/E,UAAU,GACV,MAAM,CAAC;AAEX,yDAAyD;AACzD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,cAAc,GAAG,WAAW,GAAG,uBAAuB,CAAC;IAC7D,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,MAAM,EAAE,QAAQ,CAAC;IACjB;;;;OAIG;IACH,IAAI,EAAE,QAAQ,CAAC;IACf,gFAAgF;IAChF,UAAU,EAAE,kBAAkB,CAAC;IAC/B,2EAA2E;IAC3E,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE;QACV,MAAM,EAAE,iBAAiB,CAAC;QAC1B,MAAM,EAAE,kBAAkB,CAAC;QAC3B,gEAAgE;QAChE,QAAQ,EAAE,OAAO,CAAC;QAClB,+DAA+D;QAC/D,QAAQ,EAAE,OAAO,CAAC;KACnB,CAAC;CACH;AAED,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,oDAAoD;IACpD,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,+DAA+D;IAC/D,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,8DAA8D;IAC9D,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,+DAA+D;IAC/D,WAAW,EAAE,WAAW,CAAC;CAC1B;AAqDD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,QAAQ,EAChB,UAAU,EAAE,kBAAkB,GAAG,SAAS,GACzC,QAAQ,CAOV;AAMD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,WAAW,EACnB,GAAG,SAAgB,GAClB,OAAO,CAAC,iBAAiB,CAAC,CAmH5B"}
@@ -0,0 +1,199 @@
1
+ /**
2
+ * The record normalizer: the one place that turns the three record
3
+ * layers into the record every output is built from.
4
+ *
5
+ * 1. Human source — `paths.recordsDir/<slug>.yml`, patched by
6
+ * `paths.overrides`.
7
+ * 2. Generated cache — `paths.githubCache/<slug>.json` (GitHub
8
+ * metadata and health, written by
9
+ * `grove sync github`), with a legacy inline
10
+ * `github` / `health` block and `paths.health`
11
+ * as fallbacks. Health from a stale sync resolves
12
+ * as `status: unknown` (`sync.github.maxAgeDays`).
13
+ * 3. Decisions — `paths.decisions`, which has the final say on
14
+ * visibility.
15
+ *
16
+ * `generate()` (browse, collections, SEO, sitemap, llms), `grove check`,
17
+ * `grove cleanup` and `grove readme generate` all read records through
18
+ * {@link loadNormalizedRecords}, so they cannot disagree about a
19
+ * record's fields or whether it is visible.
20
+ */
21
+ import { readdir, readFile } from 'node:fs/promises';
22
+ import { basename, join, relative, resolve } from 'node:path';
23
+ import { parse as parseYaml } from 'yaml';
24
+ import { ZodError } from 'zod';
25
+ import { githubSyncFreshnessOptions, loadGithubCache, resolveRecordGithub, } from './github-cache.js';
26
+ import { classifyHealth } from './health.js';
27
+ import { blueprintKind, decisionsFileSchema, healthFileSchema, overridesFileSchema, recordsFileSchema, recordVisibility, unwrapDecisions, unwrapHealth, unwrapOverrides, } from './schema.js';
28
+ /** Read an optional side file; a missing or invalid file yields `fallback`. */
29
+ async function readSideFile(path, cwd, parse, fallback) {
30
+ try {
31
+ const raw = await readFile(resolve(cwd, path), 'utf8');
32
+ return parse(parseYaml(raw, { schema: 'core' }) ?? {});
33
+ }
34
+ catch {
35
+ return fallback;
36
+ }
37
+ }
38
+ function loadDecisionVisibility(config, cwd) {
39
+ return readSideFile(config.paths.decisions, cwd, (raw) => new Map(unwrapDecisions(decisionsFileSchema.parse(raw)).map((d) => [d.id, d.decision.visibility])), new Map());
40
+ }
41
+ function loadHealthEntries(config, cwd) {
42
+ return readSideFile(config.paths.health, cwd, (raw) => new Map(unwrapHealth(healthFileSchema.parse(raw)).map((entry) => [entry.id, entry.health])), new Map());
43
+ }
44
+ function loadOverridePatches(config, cwd) {
45
+ return readSideFile(config.paths.overrides, cwd, (raw) => new Map(unwrapOverrides(overridesFileSchema.parse(raw)).map((entry) => [entry.id, entry.patch])), new Map());
46
+ }
47
+ /**
48
+ * Apply a `paths.decisions` visibility to a record. For project records
49
+ * the decision overwrites `health.visibility`; a project with no health
50
+ * block gets a fabricated "unknown" one from {@link classifyHealth},
51
+ * because list and index payloads read visibility from `health`. For
52
+ * resource-hub and ecosystem-map records (no `health` block) it sets the
53
+ * top-level `visibility`.
54
+ */
55
+ export function applyDecisionVisibility(record, visibility) {
56
+ if (!visibility)
57
+ return record;
58
+ if (record.kind === 'project') {
59
+ const health = record.health ?? classifyHealth(record.slug).health;
60
+ return { ...record, health: { ...health, visibility } };
61
+ }
62
+ return { ...record, visibility };
63
+ }
64
+ function isMapping(value) {
65
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
66
+ }
67
+ /**
68
+ * Discover, parse and merge every record under `config.paths.recordsDir`.
69
+ *
70
+ * Per record, lowest to highest precedence:
71
+ *
72
+ * 1. the record file (`paths.recordsDir/<slug>.yml`)
73
+ * 2. the GitHub sync cache, which supplies `github` / `health` over a
74
+ * legacy inline copy ({@link resolveRecordGithub})
75
+ * 3. the `paths.overrides` patch (shallow, top-level fields)
76
+ * 4. schema parse (`recordsFileSchema`); the slug is the file name
77
+ * 5. the `paths.health` entry, for a project record nothing above
78
+ * gave a health block
79
+ * 6. the `paths.decisions` visibility
80
+ *
81
+ * Effective visibility is then decision > health > the record's own
82
+ * `visibility` field ({@link recordVisibility}).
83
+ *
84
+ * Never throws for a bad record: a file that cannot be parsed or fails
85
+ * the schema is reported in `issues` and left out of `records`. Missing
86
+ * or invalid side files are treated as empty; `grove check` reports them.
87
+ */
88
+ export async function loadNormalizedRecords(config, cwd = process.cwd()) {
89
+ const recordsDir = resolve(cwd, config.paths.recordsDir);
90
+ const expectedKind = blueprintKind[config.blueprint];
91
+ const files = (await readdir(recordsDir).catch(() => []))
92
+ .filter((file) => file.endsWith('.yml'))
93
+ .sort();
94
+ const [githubCache, decisions, healthBySlug, patches] = await Promise.all([
95
+ loadGithubCache(config, cwd),
96
+ loadDecisionVisibility(config, cwd),
97
+ loadHealthEntries(config, cwd),
98
+ loadOverridePatches(config, cwd),
99
+ ]);
100
+ const cachePath = relative(cwd, githubCache.dir) || '.';
101
+ // A stale sync resolves as `status: unknown` rather than old values.
102
+ const freshness = githubSyncFreshnessOptions(config);
103
+ const entries = [];
104
+ for (const name of files) {
105
+ const slug = basename(name, '.yml');
106
+ const path = join(recordsDir, name);
107
+ const file = relative(cwd, path);
108
+ const entry = { slug, file, issues: [], syncStale: false };
109
+ entries.push(entry);
110
+ const fail = (code, message) => entry.issues.push({ code, severity: 'error', slug, file, message: `${slug}: ${message}` });
111
+ // `schema: 'core'` disables custom-tag interpretation: a record with
112
+ // `!!binary` / `!!js/function` must not become a host object.
113
+ let raw;
114
+ try {
115
+ raw = parseYaml(await readFile(path, 'utf8'), { schema: 'core' });
116
+ }
117
+ catch (err) {
118
+ fail('schema_error', err.message);
119
+ continue;
120
+ }
121
+ if (!isMapping(raw)) {
122
+ fail('schema_error', 'record file is empty or not a YAML mapping');
123
+ continue;
124
+ }
125
+ // Cache wins over a legacy inline copy; a disagreement is a second
126
+ // source of truth, so name the fields.
127
+ const resolved = resolveRecordGithub(raw, githubCache.entries.get(slug), freshness);
128
+ entry.syncStale = resolved.syncStale !== undefined;
129
+ if (resolved.conflicts.length > 0) {
130
+ entry.issues.push({
131
+ code: 'github_cache_mismatch',
132
+ severity: 'warning',
133
+ slug,
134
+ file,
135
+ message: `${slug}: inline github/health disagrees with ${cachePath}/${slug}.json — ${resolved.conflicts.join(', ')}. The cache wins; run \`grove migrate github-cache\` to drop the inline copy.`,
136
+ });
137
+ }
138
+ const merged = resolved.record;
139
+ if (!merged.kind)
140
+ merged.kind = expectedKind;
141
+ const patch = patches.get(slug);
142
+ let base;
143
+ try {
144
+ base = recordsFileSchema.parse(patch ? { ...merged, ...patch } : merged);
145
+ }
146
+ catch (err) {
147
+ if (err instanceof ZodError) {
148
+ for (const issue of err.issues) {
149
+ const where = issue.path.length > 0 ? issue.path.join('.') : '(root)';
150
+ fail('zod_error', `${where} ${issue.message}`);
151
+ }
152
+ }
153
+ else {
154
+ fail('schema_error', err.message);
155
+ }
156
+ continue;
157
+ }
158
+ base.slug = slug;
159
+ let healthSource = patch && 'health' in patch
160
+ ? 'override'
161
+ : resolved.health === 'none'
162
+ ? 'none'
163
+ : resolved.health;
164
+ let record = base;
165
+ if (record.kind === 'project' && !record.health) {
166
+ healthSource = 'none';
167
+ const fromFile = healthBySlug.get(slug);
168
+ if (fromFile) {
169
+ record = { ...record, health: fromFile };
170
+ healthSource = 'file';
171
+ }
172
+ }
173
+ const decision = decisions.get(slug);
174
+ if (decision && record.kind === 'project' && !record.health)
175
+ healthSource = 'decision';
176
+ record = applyDecisionVisibility(record, decision);
177
+ entry.record = {
178
+ slug,
179
+ file,
180
+ record,
181
+ base,
182
+ visibility: recordVisibility(record),
183
+ declaredSlug: raw.slug,
184
+ provenance: {
185
+ github: resolved.github,
186
+ health: healthSource,
187
+ decision: decision !== undefined,
188
+ override: patch !== undefined,
189
+ },
190
+ };
191
+ }
192
+ return {
193
+ records: entries.flatMap((entry) => (entry.record ? [entry.record] : [])),
194
+ entries,
195
+ issues: entries.flatMap((entry) => entry.issues),
196
+ githubCache,
197
+ };
198
+ }
199
+ //# sourceMappingURL=normalize-records.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-records.js","sourceRoot":"","sources":["../src/normalize-records.ts"],"names":[],"mappings":"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"}