@grove-dev/core 0.1.4 → 0.2.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.
@@ -1,55 +1,43 @@
1
- import { type CuratedConfig } from "./schema.js";
1
+ import { type GroveConfig } from "./schema.js";
2
2
  /**
3
- * The full payload written to data/generated/apps.full.json.
3
+ * The full payload written to data/generated/records.full.json.
4
4
  * Carries every normalized record, regardless of visibility.
5
5
  */
6
- export interface AppsFullPayload {
6
+ export interface RecordsFullPayload {
7
7
  schemaVersion: number;
8
+ blueprint: string;
8
9
  generatedAt: string;
9
- totalApps: number;
10
- visibleApps: number;
11
- apps: Array<Record<string, unknown>>;
10
+ totalRecords: number;
11
+ visibleRecords: number;
12
+ records: Array<Record<string, unknown>>;
12
13
  }
13
14
  /**
14
- * The slim payload written to data/generated/apps.index.json.
15
+ * The slim payload written to data/generated/records.index.json.
15
16
  * Carries only what list and search pages need.
16
17
  */
17
- export interface AppsIndexPayload {
18
+ export interface RecordsIndexPayload {
18
19
  schemaVersion: number;
20
+ blueprint: string;
19
21
  generatedAt: string;
20
- totalApps: number;
21
- apps: Array<Record<string, unknown>>;
22
+ totalRecords: number;
23
+ records: Array<Record<string, unknown>>;
22
24
  }
23
25
  /**
24
- * The TS file written to src/data/config.ts. Sites import this for
25
- * a typed view of curated.config.ts. Auto-generated; do not edit.
26
- */
27
- export interface SiteConfigTsInput {
28
- name: string;
29
- tagline: string;
30
- description: string;
31
- siteUrl: string;
32
- repoUrl: string;
33
- itemLabel: string;
34
- }
35
- export declare function buildSiteConfigTs(input: SiteConfigTsInput): string;
36
- /**
37
- * Read every apps/*.yml in the project, normalize, and build:
38
- * - data/generated/apps.full.json (full records, all visibility)
39
- * - data/generated/apps.index.json (slim, visible-only)
40
- * - data/generated/apps.json (compatibility alias of apps.full.json)
41
- * - src/data/config.ts (typed view of curated.config.ts)
26
+ * `generate` reads every records/*.yml in the project, normalizes them
27
+ * via the blueprint schema, and writes:
28
+ * - data/generated/records.full.json (full records, all visibility)
29
+ * - data/generated/records.index.json (slim, visible-only)
30
+ * - data/generated/records.json (alias of records.full.json)
42
31
  *
43
- * Returns a small summary; throws on schema errors.
32
+ * Returns file paths and counters; throws on schema errors.
44
33
  */
45
- export interface BuildDataResult {
46
- totalApps: number;
47
- visibleApps: number;
34
+ export interface GenerateResult {
35
+ totalRecords: number;
36
+ visibleRecords: number;
48
37
  fullPath: string;
49
38
  indexPath: string;
50
39
  aliasPath: string;
51
- configTsPath: string;
52
40
  errors: string[];
53
41
  }
54
- export declare function buildData(cwd?: string, config?: CuratedConfig): Promise<BuildDataResult>;
42
+ export declare function generate(cwd?: string, config?: GroveConfig): Promise<GenerateResult>;
55
43
  //# sourceMappingURL=build-data.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-data.d.ts","sourceRoot":"","sources":["../src/build-data.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,aAAa,EAInB,MAAM,aAAa,CAAC;AAGrB;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACtC;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACtC;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAwBlE;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAsB,SAAS,CAC7B,GAAG,SAAgB,EACnB,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,eAAe,CAAC,CAyF1B"}
1
+ {"version":3,"file":"build-data.d.ts","sourceRoot":"","sources":["../src/build-data.ts"],"names":[],"mappings":"AAGA,OAAO,EAKL,KAAK,WAAW,EAEjB,MAAM,aAAa,CAAC;AAGrB;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACzC;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACzC;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAsB,QAAQ,CAC5B,GAAG,SAAgB,EACnB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC,CA8FzB"}
@@ -1,115 +1,96 @@
1
1
  import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { basename, join, resolve } from "node:path";
3
- import { normalizeAppRecord, parseAppYaml, toIndexApp, } from "./schema.js";
3
+ import { parse as parseYaml } from "yaml";
4
+ import { blueprintKind, recordsFileSchema, toIndexRecord, unwrapRecords, } from "./schema.js";
4
5
  import { loadConfig } from "./config.js";
5
- export function buildSiteConfigTs(input) {
6
- return `/**
7
- * AUTO-GENERATED by grove build-data — do not edit by hand.
8
- * Re-run \`grove build-data\` after changing curated.config.ts.
9
- */
10
-
11
- export type SiteConfig = {
12
- name: string;
13
- tagline: string;
14
- description: string;
15
- siteUrl: string;
16
- repoUrl: string;
17
- itemLabel: string;
18
- };
19
-
20
- export const siteConfig: SiteConfig = {
21
- name: ${JSON.stringify(input.name)},
22
- tagline: ${JSON.stringify(input.tagline)},
23
- description: ${JSON.stringify(input.description)},
24
- siteUrl: ${JSON.stringify(input.siteUrl)},
25
- repoUrl: ${JSON.stringify(input.repoUrl)},
26
- itemLabel: ${JSON.stringify(input.itemLabel)},
27
- };
28
- `;
29
- }
30
- export async function buildData(cwd = process.cwd(), config) {
6
+ export async function generate(cwd = process.cwd(), config) {
31
7
  const cfg = config ?? (await loadConfig(cwd));
32
- const appsDir = resolve(cwd, cfg.paths.appsDir);
8
+ const recordsDir = resolve(cwd, cfg.paths.recordsDir);
33
9
  const outDir = resolve(cwd, cfg.paths.generatedDir);
34
10
  await mkdir(outDir, { recursive: true });
35
- let entries = [];
36
- try {
37
- entries = await readdir(appsDir);
38
- }
39
- catch {
40
- entries = [];
41
- }
11
+ // Re-emit the site config as JSON alongside the records so the
12
+ // Astro (or any framework) template can pick up the user's
13
+ // branding, theme, and nav without parsing `grove.config.ts`
14
+ // at render time. The CLI runs `generate` ahead of `build`,
15
+ // so this stays in sync with the consumer's config edits.
16
+ const siteConfigPayload = {
17
+ blueprint: cfg.blueprint,
18
+ name: cfg.site.name,
19
+ tagline: cfg.site.tagline,
20
+ description: cfg.site.description ?? cfg.site.tagline,
21
+ siteUrl: cfg.site.url ?? "https://example.com",
22
+ repoUrl: cfg.site.repoUrl ?? "",
23
+ nav: cfg.nav,
24
+ theme: cfg.theme,
25
+ integrations: cfg.integrations,
26
+ };
27
+ await writeFile(join(outDir, "site-config.json"), JSON.stringify(siteConfigPayload, null, 2), "utf8");
28
+ const expectedKind = blueprintKind[cfg.blueprint];
29
+ const entries = await readdir(recordsDir).catch(() => []);
42
30
  const files = entries.filter((f) => f.endsWith(".yml")).sort();
43
- const apps = [];
31
+ const out = [];
44
32
  const errors = [];
45
33
  for (const file of files) {
46
34
  const fileSlug = basename(file, ".yml");
47
35
  try {
48
- const text = await readFile(join(appsDir, file), "utf8");
49
- const raw = parseAppYaml(text, fileSlug);
50
- const app = normalizeAppRecord(raw, fileSlug);
51
- if (app.slug !== fileSlug) {
52
- app.slug = fileSlug;
53
- }
54
- apps.push(app);
36
+ const text = await readFile(join(recordsDir, file), "utf8");
37
+ const raw = (parseYaml(text) ?? {});
38
+ if (!raw.kind)
39
+ raw.kind = expectedKind;
40
+ const normalized = unwrapRecords(recordsFileSchema.parse([raw]))[0];
41
+ normalized.slug = fileSlug;
42
+ out.push(normalized);
55
43
  }
56
44
  catch (err) {
57
45
  errors.push(`${file}: ${err.message}`);
58
46
  }
59
47
  }
60
48
  if (errors.length > 0) {
61
- const e = new Error(`build-data failed: ${errors.length} schema error(s)`);
49
+ const e = new Error(`generate failed: ${errors.length} schema error(s)`);
62
50
  e.details = errors;
63
51
  throw e;
64
52
  }
65
- apps.sort((a, b) => {
66
- const sa = a.stars ?? 0;
67
- const sb = b.stars ?? 0;
68
- if (sb !== sa)
69
- return sb - sa;
70
- return (a.name ?? "").localeCompare(b.name ?? "");
53
+ out.sort((a, b) => nameOf(a).localeCompare(nameOf(b)));
54
+ const indexRecords = out
55
+ .map((record) => toIndexRecord(record))
56
+ .filter((r) => {
57
+ const vis = r.visibility;
58
+ return vis !== "hide" && vis !== "remove";
71
59
  });
72
- const indexApps = apps
73
- .map((app) => toIndexApp(app))
74
- .filter((a) => a.visibility !== "hide");
75
60
  const generatedAt = new Date().toISOString();
76
61
  const fullPayload = {
77
62
  schemaVersion: 1,
63
+ blueprint: cfg.blueprint,
78
64
  generatedAt,
79
- totalApps: apps.length,
80
- visibleApps: indexApps.length,
81
- apps: apps,
65
+ totalRecords: out.length,
66
+ visibleRecords: indexRecords.length,
67
+ records: out,
82
68
  };
83
69
  const indexPayload = {
84
70
  schemaVersion: 1,
71
+ blueprint: cfg.blueprint,
85
72
  generatedAt,
86
- totalApps: indexApps.length,
87
- apps: indexApps,
73
+ totalRecords: indexRecords.length,
74
+ records: indexRecords,
88
75
  };
89
- const fullPath = join(outDir, "apps.full.json");
90
- const indexPath = join(outDir, "apps.index.json");
91
- const aliasPath = join(outDir, "apps.json");
76
+ const fullPath = join(outDir, "records.full.json");
77
+ const indexPath = join(outDir, "records.index.json");
78
+ const aliasPath = join(outDir, "records.json");
92
79
  await writeFile(fullPath, JSON.stringify(fullPayload, null, 2), "utf8");
93
80
  await writeFile(indexPath, JSON.stringify(indexPayload, null, 2), "utf8");
94
81
  await writeFile(aliasPath, JSON.stringify(fullPayload, null, 2), "utf8");
95
- const configTsPath = resolve(cwd, "src/data/config.ts");
96
- const configTs = buildSiteConfigTs({
97
- name: cfg.name,
98
- tagline: cfg.tagline,
99
- description: cfg.description ?? cfg.tagline,
100
- siteUrl: cfg.siteUrl ?? "https://example.com",
101
- repoUrl: cfg.repoUrl ?? "",
102
- itemLabel: cfg.itemLabel,
103
- });
104
- await writeFile(configTsPath, configTs, "utf8");
105
82
  return {
106
- totalApps: apps.length,
107
- visibleApps: indexApps.length,
83
+ totalRecords: out.length,
84
+ visibleRecords: indexRecords.length,
108
85
  fullPath,
109
86
  indexPath,
110
87
  aliasPath,
111
- configTsPath,
112
88
  errors,
113
89
  };
114
90
  }
91
+ function nameOf(record) {
92
+ if (record.kind === "resource")
93
+ return record.title;
94
+ return record.name;
95
+ }
115
96
  //# sourceMappingURL=build-data.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-data.js","sourceRoot":"","sources":["../src/build-data.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build-data.js","sourceRoot":"","sources":["../src/build-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,aAAa,GAGd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA6CzC,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EACnB,MAAoB;IAEpB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACpD,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzC,+DAA+D;IAC/D,2DAA2D;IAC3D,6DAA6D;IAC7D,4DAA4D;IAC5D,0DAA0D;IAC1D,MAAM,iBAAiB,GAAG;QACxB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI;QACnB,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO;QACzB,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO;QACrD,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,qBAAqB;QAC9C,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE;QAC/B,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,YAAY,EAAE,GAAG,CAAC,YAAY;KAC/B,CAAC;IACF,MAAM,SAAS,CACb,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAChC,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC,EAC1C,MAAM,CACP,CAAC;IAEF,MAAM,YAAY,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAc,CAAC,CAAC;IACtE,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAE/D,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;YAC5D,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAA4B,CAAC;YAC/D,IAAI,CAAC,GAAG,CAAC,IAAI;gBAAE,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC;YACvC,MAAM,UAAU,GAAG,aAAa,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpE,UAAU,CAAC,IAAI,GAAG,QAAQ,CAAC;YAC3B,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACvB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,oBAAoB,MAAM,CAAC,MAAM,kBAAkB,CAAC,CAAC;QACxE,CAAoC,CAAC,OAAO,GAAG,MAAM,CAAC;QACvD,MAAM,CAAC,CAAC;IACV,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvD,MAAM,YAAY,GAAG,GAAG;SACrB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;SACtC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACZ,MAAM,GAAG,GAAI,CAA6B,CAAC,UAAU,CAAC;QACtD,OAAO,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,QAAQ,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEL,MAAM,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC7C,MAAM,WAAW,GAAuB;QACtC,aAAa,EAAE,CAAC;QAChB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,WAAW;QACX,YAAY,EAAE,GAAG,CAAC,MAAM;QACxB,cAAc,EAAE,YAAY,CAAC,MAAM;QACnC,OAAO,EAAE,GAAgD;KAC1D,CAAC;IACF,MAAM,YAAY,GAAwB;QACxC,aAAa,EAAE,CAAC;QAChB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,WAAW;QACX,YAAY,EAAE,YAAY,CAAC,MAAM;QACjC,OAAO,EAAE,YAAyD;KACnE,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC/C,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACxE,MAAM,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC1E,MAAM,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAEzE,OAAO;QACL,YAAY,EAAE,GAAG,CAAC,MAAM;QACxB,cAAc,EAAE,YAAY,CAAC,MAAM;QACnC,QAAQ;QACR,SAAS;QACT,SAAS;QACT,MAAM;KACP,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,MAAgB;IAC9B,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC;IACpD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
package/dist/config.d.ts CHANGED
@@ -1,5 +1,16 @@
1
- import { type CuratedConfig } from "./schema.js";
2
- export type { CuratedConfig };
3
- export declare function loadConfig(cwd?: string, configPath?: string): Promise<CuratedConfig>;
4
- export declare function defineConfig(config: CuratedConfig): CuratedConfig;
1
+ import { type GroveConfig } from "./schema.js";
2
+ export type { GroveConfig };
3
+ /**
4
+ * Load the Grove project config. The config file is the single source
5
+ * of truth for blueprint, site metadata, paths, integrations, theme,
6
+ * and component overrides.
7
+ *
8
+ * Default name: `grove.config.ts`. Override with the second arg.
9
+ */
10
+ export declare function loadConfig(cwd?: string, configPath?: string): Promise<GroveConfig>;
11
+ /**
12
+ * Define and validate a Grove config. Used at the bottom of a
13
+ * `grove.config.ts` file so editors get good type hints.
14
+ */
15
+ export declare function defineConfig(config: GroveConfig): GroveConfig;
5
16
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEtE,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,wBAAsB,UAAU,CAAC,GAAG,SAAgB,EAAE,UAAU,SAAsB,GAAG,OAAO,CAAC,aAAa,CAAC,CAM9G;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAEjE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAElE,YAAY,EAAE,WAAW,EAAE,CAAC;AAE5B;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,GAAG,SAAgB,EACnB,UAAU,SAAoB,GAC7B,OAAO,CAAC,WAAW,CAAC,CAMtB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAE7D"}
package/dist/config.js CHANGED
@@ -1,14 +1,25 @@
1
1
  import { resolve } from "node:path";
2
2
  import { createJiti } from "jiti";
3
- import { curatedConfigSchema } from "./schema.js";
4
- export async function loadConfig(cwd = process.cwd(), configPath = "curated.config.ts") {
3
+ import { groveConfigSchema } from "./schema.js";
4
+ /**
5
+ * Load the Grove project config. The config file is the single source
6
+ * of truth for blueprint, site metadata, paths, integrations, theme,
7
+ * and component overrides.
8
+ *
9
+ * Default name: `grove.config.ts`. Override with the second arg.
10
+ */
11
+ export async function loadConfig(cwd = process.cwd(), configPath = "grove.config.ts") {
5
12
  const resolved = resolve(cwd, configPath);
6
13
  const jiti = createJiti(import.meta.url);
7
- const mod = await jiti.import(resolved, { default: true });
14
+ const mod = (await jiti.import(resolved, { default: true }));
8
15
  const raw = mod.default ?? mod.config ?? mod;
9
- return curatedConfigSchema.parse(raw);
16
+ return groveConfigSchema.parse(raw);
10
17
  }
18
+ /**
19
+ * Define and validate a Grove config. Used at the bottom of a
20
+ * `grove.config.ts` file so editors get good type hints.
21
+ */
11
22
  export function defineConfig(config) {
12
- return curatedConfigSchema.parse(config);
23
+ return groveConfigSchema.parse(config);
13
24
  }
14
25
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAsB,MAAM,aAAa,CAAC;AAItE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,GAAG,mBAAmB;IACpF,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAA4B,CAAC;IACtF,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC;IAC7C,OAAO,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAqB;IAChD,OAAO,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC3C,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAoB,MAAM,aAAa,CAAC;AAIlE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EACnB,UAAU,GAAG,iBAAiB;IAE9B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAA4B,CAAC;IACxF,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC;IAC7C,OAAO,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,OAAO,iBAAiB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC"}
@@ -1,28 +1,31 @@
1
- import { type AppRecord } from "./schema.js";
2
- import { type CuratedConfig } from "./config.js";
3
- export interface ReviewCandidate {
1
+ import { type GroveConfig, type Resource } from "./schema.js";
2
+ export interface CleanupCandidate {
4
3
  slug: string;
5
4
  name: string;
6
- repoUrl: string;
5
+ url: string;
7
6
  status: string;
8
7
  tier: string;
9
8
  staleReason: string | null;
10
9
  lastCommitAt: string | null;
11
10
  stars: number;
12
11
  }
13
- export interface ReviewReport {
12
+ export interface CleanupReport {
14
13
  generatedAt: string;
14
+ blueprint: string;
15
15
  totalCandidates: number;
16
- candidates: ReviewCandidate[];
16
+ candidates: CleanupCandidate[];
17
17
  }
18
- /** Compute the set of review candidates from normalized app records. */
19
- export declare function pickReviewCandidates(apps: AppRecord[]): AppRecord[];
18
+ /** Filter records down to the ones that need a human curation pass. */
19
+ export declare function pickCleanupCandidates(records: Resource[]): Resource[];
20
20
  /**
21
- * Read every apps/*.yml, normalize, then write data/generated/review-report.json
22
- * with cleanup candidates (unknown / needs_review / cleanupCandidate).
21
+ * Read every record YAML under `config.paths.recordsDir`, normalize,
22
+ * then write `data/generated/cleanup-report.json` with the list of
23
+ * records that need human attention (stale / unknown / cleanup).
24
+ *
25
+ * V1 name for what was previously `review`.
23
26
  */
24
- export declare function buildReviewReport(cwd?: string, config?: CuratedConfig): Promise<{
25
- report: ReviewReport;
27
+ export declare function cleanupStale(cwd?: string, config?: GroveConfig): Promise<{
28
+ report: CleanupReport;
26
29
  path: string;
27
30
  }>;
28
31
  //# sourceMappingURL=decisions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decisions.d.ts","sourceRoot":"","sources":["../src/decisions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAoC,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,KAAK,aAAa,EAAc,MAAM,aAAa,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAeD,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAOnE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,SAAgB,EACnB,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA6BjD"}
1
+ {"version":3,"file":"decisions.d.ts","sourceRoot":"","sources":["../src/decisions.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAsBD,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAOrE;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,GAAG,SAAgB,EACnB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAmClD"}
package/dist/decisions.js CHANGED
@@ -1,56 +1,76 @@
1
1
  import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { basename, join, resolve } from "node:path";
3
- import { normalizeAppRecord, parseAppYaml } from "./schema.js";
3
+ import { parse as parseYaml } from "yaml";
4
+ import { blueprintKind, recordsFileSchema, unwrapRecords, } from "./schema.js";
4
5
  import { loadConfig } from "./config.js";
5
- function toCandidate(app) {
6
+ function toCandidate(record) {
7
+ const name = record.kind === "resource" ? record.title : record.name;
8
+ const url = record.links?.github ?? record.links?.website ?? record.links?.source ?? "";
9
+ const health = record
10
+ .health;
11
+ const gh = record
12
+ .github?.repository;
6
13
  return {
7
- slug: app.slug,
8
- name: app.name,
9
- repoUrl: app.repoUrl,
10
- status: app.status,
11
- tier: app.tier,
12
- staleReason: app.staleReason,
13
- lastCommitAt: app.lastCommitAt ?? null,
14
- stars: app.stars ?? 0,
14
+ slug: record.slug,
15
+ name,
16
+ url,
17
+ status: health?.status ?? "unknown",
18
+ tier: health?.tier ?? "experimental",
19
+ staleReason: health?.staleReason ?? null,
20
+ lastCommitAt: gh?.pushed_at ?? null,
21
+ stars: gh?.stargazers_count ?? 0,
15
22
  };
16
23
  }
17
- /** Compute the set of review candidates from normalized app records. */
18
- export function pickReviewCandidates(apps) {
19
- return apps.filter((app) => app.cleanupCandidate ||
20
- app.status === "unknown" ||
21
- app.status === "needs_review");
24
+ /** Filter records down to the ones that need a human curation pass. */
25
+ export function pickCleanupCandidates(records) {
26
+ return records.filter((r) => {
27
+ const health = r.health;
28
+ if (health?.cleanupCandidate)
29
+ return true;
30
+ if (health?.status === "unknown" || health?.status === "needs_review")
31
+ return true;
32
+ return false;
33
+ });
22
34
  }
23
35
  /**
24
- * Read every apps/*.yml, normalize, then write data/generated/review-report.json
25
- * with cleanup candidates (unknown / needs_review / cleanupCandidate).
36
+ * Read every record YAML under `config.paths.recordsDir`, normalize,
37
+ * then write `data/generated/cleanup-report.json` with the list of
38
+ * records that need human attention (stale / unknown / cleanup).
39
+ *
40
+ * V1 name for what was previously `review`.
26
41
  */
27
- export async function buildReviewReport(cwd = process.cwd(), config) {
42
+ export async function cleanupStale(cwd = process.cwd(), config) {
28
43
  const cfg = config ?? (await loadConfig(cwd));
29
- const appsDir = resolve(cwd, cfg.paths.appsDir);
44
+ const recordsDir = resolve(cwd, cfg.paths.recordsDir);
30
45
  const outDir = resolve(cwd, cfg.paths.generatedDir);
31
46
  await mkdir(outDir, { recursive: true });
32
- let entries = [];
33
- try {
34
- entries = await readdir(appsDir);
35
- }
36
- catch {
37
- entries = [];
38
- }
47
+ const expectedKind = blueprintKind[cfg.blueprint];
48
+ const entries = await readdir(recordsDir).catch(() => []);
39
49
  const files = entries.filter((f) => f.endsWith(".yml")).sort();
40
- const apps = [];
50
+ const records = [];
41
51
  for (const file of files) {
42
52
  const fileSlug = basename(file, ".yml");
43
- const text = await readFile(join(appsDir, file), "utf8");
44
- const raw = parseAppYaml(text, fileSlug);
45
- apps.push(normalizeAppRecord(raw, fileSlug));
53
+ const text = await readFile(join(recordsDir, file), "utf8");
54
+ const raw = (parseYaml(text) ?? {});
55
+ if (!raw.kind)
56
+ raw.kind = expectedKind;
57
+ try {
58
+ const normalized = unwrapRecords(recordsFileSchema.parse([raw]))[0];
59
+ normalized.slug = fileSlug;
60
+ records.push(normalized);
61
+ }
62
+ catch {
63
+ // skip — validation surfaces the error
64
+ }
46
65
  }
47
- const candidates = pickReviewCandidates(apps).map(toCandidate);
66
+ const candidates = pickCleanupCandidates(records).map(toCandidate);
48
67
  const report = {
49
68
  generatedAt: new Date().toISOString(),
69
+ blueprint: cfg.blueprint,
50
70
  totalCandidates: candidates.length,
51
71
  candidates,
52
72
  };
53
- const path = join(outDir, "review-report.json");
73
+ const path = join(outDir, "cleanup-report.json");
54
74
  await writeFile(path, JSON.stringify(report, null, 2), "utf8");
55
75
  return { report, path };
56
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"decisions.js","sourceRoot":"","sources":["../src/decisions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAkB,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAsB,UAAU,EAAE,MAAM,aAAa,CAAC;AAmB7D,SAAS,WAAW,CAAC,GAAc;IACjC,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,IAAI;QACtC,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;KACtB,CAAC;AACJ,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,oBAAoB,CAAC,IAAiB;IACpD,OAAO,IAAI,CAAC,MAAM,CAChB,CAAC,GAAG,EAAE,EAAE,CACN,GAAG,CAAC,gBAAgB;QACpB,GAAG,CAAC,MAAM,KAAK,SAAS;QACxB,GAAG,CAAC,MAAM,KAAK,cAAc,CAChC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EACnB,MAAsB;IAEtB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACpD,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzC,IAAI,OAAO,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,EAAE,CAAC;IACf,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/D,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QACzD,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,MAAM,UAAU,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAiB;QAC3B,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,eAAe,EAAE,UAAU,CAAC,MAAM;QAClC,UAAU;KACX,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAChD,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/D,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1B,CAAC"}
1
+ {"version":3,"file":"decisions.js","sourceRoot":"","sources":["../src/decisions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,aAAa,GAGd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAoBzC,SAAS,WAAW,CAAC,MAAgB;IACnC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;IACrE,MAAM,GAAG,GACP,MAAM,CAAC,KAAK,EAAE,MAAM,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC;IAC9E,MAAM,MAAM,GAAI,MAAuF;SACpG,MAAM,CAAC;IACV,MAAM,EAAE,GAAI,MAA0F;SACnG,MAAM,EAAE,UAAU,CAAC;IACtB,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI;QACJ,GAAG;QACH,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,SAAS;QACnC,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,cAAc;QACpC,WAAW,EAAE,MAAM,EAAE,WAAW,IAAI,IAAI;QACxC,YAAY,EAAE,EAAE,EAAE,SAAS,IAAI,IAAI;QACnC,KAAK,EAAE,EAAE,EAAE,gBAAgB,IAAI,CAAC;KACjC,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,qBAAqB,CAAC,OAAmB;IACvD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAC1B,MAAM,MAAM,GAAI,CAAkE,CAAC,MAAM,CAAC;QAC1F,IAAI,MAAM,EAAE,gBAAgB;YAAE,OAAO,IAAI,CAAC;QAC1C,IAAI,MAAM,EAAE,MAAM,KAAK,SAAS,IAAI,MAAM,EAAE,MAAM,KAAK,cAAc;YAAE,OAAO,IAAI,CAAC;QACnF,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EACnB,MAAoB;IAEpB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACpD,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzC,MAAM,YAAY,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAc,CAAC,CAAC;IACtE,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAE/D,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QAC5D,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAA4B,CAAC;QAC/D,IAAI,CAAC,GAAG,CAAC,IAAI;YAAE,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,aAAa,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpE,UAAU,CAAC,IAAI,GAAG,QAAQ,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,uCAAuC;QACzC,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACnE,MAAM,MAAM,GAAkB;QAC5B,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,eAAe,EAAE,UAAU,CAAC,MAAM;QAClC,UAAU;KACX,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IACjD,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/D,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1B,CAAC"}
package/dist/enrich.d.ts CHANGED
@@ -7,8 +7,8 @@
7
7
  * the page render doesn't include the standard "X license" link text.
8
8
  *
9
9
  * The returned shape is compatible with the GitHub REST `repository`
10
- * block used in `data/apps/<slug>.yml`, so a subsequent token-backed
11
- * sync can fill in the rest of the fields.
10
+ * block used in `data/records/<slug>.yml` for `kind: project` records,
11
+ * so a subsequent token-backed sync can fill in the rest of the fields.
12
12
  */
13
13
  export interface EnrichedFields {
14
14
  license: string | null;
package/dist/enrich.js CHANGED
@@ -7,8 +7,8 @@
7
7
  * the page render doesn't include the standard "X license" link text.
8
8
  *
9
9
  * The returned shape is compatible with the GitHub REST `repository`
10
- * block used in `data/apps/<slug>.yml`, so a subsequent token-backed
11
- * sync can fill in the rest of the fields.
10
+ * block used in `data/records/<slug>.yml` for `kind: project` records,
11
+ * so a subsequent token-backed sync can fill in the rest of the fields.
12
12
  */
13
13
  import { getOwnerRepoFromUrl } from "./schema.js";
14
14
  const HEADERS = {
@@ -1,3 +1,4 @@
1
- import { type ImportResult } from "./markdown.js";
2
- export declare function importAwesomeList(input: string): Promise<ImportResult>;
1
+ import { importAwesomeList, writeImportedRecords, type ImportResult } from "./markdown.js";
2
+ export { importAwesomeList, writeImportedRecords };
3
+ export type { ImportResult };
3
4
  //# sourceMappingURL=importer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"importer.d.ts","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAQxE,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAc5E"}
1
+ {"version":3,"file":"importer.d.ts","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,CAAC"}
package/dist/importer.js CHANGED
@@ -1,24 +1,3 @@
1
- import { basename, resolve } from "node:path";
2
- import { readFile } from "node:fs/promises";
3
- import { parseAwesomeMarkdown } from "./markdown.js";
4
- function githubReadmeUrl(input) {
5
- const match = input.match(/^https?:\/\/github\.com\/([^/\s]+)\/([^/#?\s]+)(?:\/)?$/i);
6
- if (!match)
7
- return undefined;
8
- return `https://raw.githubusercontent.com/${match[1]}/${match[2]}/HEAD/README.md`;
9
- }
10
- export async function importAwesomeList(input) {
11
- const remote = githubReadmeUrl(input) ?? (/^https?:\/\//.test(input) ? input : undefined);
12
- if (remote) {
13
- const response = await fetch(remote);
14
- if (!response.ok) {
15
- throw new Error(`Could not fetch ${remote}: ${response.status} ${response.statusText}`);
16
- }
17
- const text = await response.text();
18
- return parseAwesomeMarkdown(text, { file: "sources/README.md", sourceUrl: input });
19
- }
20
- const path = resolve(input);
21
- const text = await readFile(path, "utf8");
22
- return parseAwesomeMarkdown(text, { file: basename(path) });
23
- }
1
+ import { importAwesomeList, writeImportedRecords, } from "./markdown.js";
2
+ export { importAwesomeList, writeImportedRecords };
24
3
  //# sourceMappingURL=importer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"importer.js","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAqB,MAAM,eAAe,CAAC;AAExE,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;IACtF,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,OAAO,qCAAqC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,iBAAiB,CAAC;AACpF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAa;IACnD,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC1F,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QAC1F,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,OAAO,oBAAoB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IACrF,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1C,OAAO,oBAAoB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC9D,CAAC"}
1
+ {"version":3,"file":"importer.js","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,oBAAoB,GAErB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,CAAC"}