@grimoire-rs/indexer 0.3.1 → 0.3.3
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/dist/config.d.ts +14 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +22 -0
- package/dist/config.js.map +1 -1
- package/dist/renderer/astro/components/Catalog.js +32 -13
- package/dist/renderer/astro/components/Catalog.tsx +32 -15
- package/dist/renderer/astro/layouts/Base.astro +28 -5
- package/package.json +2 -1
package/dist/config.d.ts
CHANGED
|
@@ -66,6 +66,20 @@ export interface SiteConfig {
|
|
|
66
66
|
* link alone.
|
|
67
67
|
*/
|
|
68
68
|
footerNote?: string | null;
|
|
69
|
+
/**
|
|
70
|
+
* Extra footer links, rendered after the raw-data line as a plain row.
|
|
71
|
+
*
|
|
72
|
+
* Exists because `footerNote` is text, and the thing an index most often
|
|
73
|
+
* has to put in a footer is not a sentence but a link: a privacy notice, an
|
|
74
|
+
* imprint, a code of conduct. Whether any of those are legally required
|
|
75
|
+
* depends on where the index runner lives and what the index is for, so the
|
|
76
|
+
* renderer takes no position and ships none by default — it just stops the
|
|
77
|
+
* answer being "fork the layout".
|
|
78
|
+
*/
|
|
79
|
+
footerLinks?: Array<{
|
|
80
|
+
label: string;
|
|
81
|
+
href: string;
|
|
82
|
+
}>;
|
|
69
83
|
/**
|
|
70
84
|
* "Built with ♥ using Grimoire" in the footer, linking to grimoire.rs.
|
|
71
85
|
* `false` removes it — an index runner is not obliged to advertise the
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAUA,+DAA+D;AAC/D,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;AAEtD,eAAO,MAAM,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAUA,+DAA+D;AAC/D,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;AAEtD,eAAO,MAAM,cAAc,EAAE,kBAwC5B,CAAC;AAEF,2EAA2E;AAC3E,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAoGD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAelE;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,kBAAkB,CAWpE"}
|
package/dist/config.js
CHANGED
|
@@ -43,6 +43,7 @@ export const DEFAULT_CONFIG = {
|
|
|
43
43
|
// old default: "pointers, not payloads", which explains the architecture
|
|
44
44
|
// to someone who did not ask, and the em dash holding it on.
|
|
45
45
|
footerNote: "index metadata is CC0 · packages live on OCI registries",
|
|
46
|
+
footerLinks: [],
|
|
46
47
|
attribution: true,
|
|
47
48
|
customCss: null,
|
|
48
49
|
};
|
|
@@ -86,6 +87,27 @@ function validate(raw) {
|
|
|
86
87
|
if (cfg.attribution !== undefined && typeof cfg.attribution !== "boolean") {
|
|
87
88
|
fail("attribution must be a boolean");
|
|
88
89
|
}
|
|
90
|
+
if (cfg.footerLinks !== undefined) {
|
|
91
|
+
if (!Array.isArray(cfg.footerLinks))
|
|
92
|
+
fail("footerLinks must be an array");
|
|
93
|
+
for (const [i, entry] of cfg.footerLinks.entries()) {
|
|
94
|
+
const at = `footerLinks[${i}]`;
|
|
95
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) {
|
|
96
|
+
fail(`${at} must be an object with label and href`);
|
|
97
|
+
}
|
|
98
|
+
const { label, href } = entry;
|
|
99
|
+
if (typeof label !== "string" || label.trim() === "") {
|
|
100
|
+
fail(`${at}.label must be a non-empty string`);
|
|
101
|
+
}
|
|
102
|
+
// Same rule the other URL keys get. A relative href would resolve
|
|
103
|
+
// against whichever page the footer happens to be on — `/p/<ns>/<pkg>/`
|
|
104
|
+
// is two levels deep — so it is refused rather than silently 404ing
|
|
105
|
+
// from half the site.
|
|
106
|
+
if (typeof href !== "string" || !/^https?:\/\//i.test(href)) {
|
|
107
|
+
fail(`${at}.href must be an http(s) URL`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
89
111
|
// Lands in `src`. A site-root path is the normal case; an absolute URL is
|
|
90
112
|
// allowed for a logo already hosted elsewhere. Anything else — a bare
|
|
91
113
|
// relative path that would break on a subpath deployment, or a `javascript:`
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,sCAAsC;AAEtC,sEAAsE;AACtE,0EAA0E;AAC1E,0EAA0E;AAC1E,0BAA0B;AAC1B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,+DAA+D;AAC/D,MAAM,CAAC,MAAM,WAAW,GAAG,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -120,12 +120,21 @@ function CopyButton({ command, variant = "default", name, }) {
|
|
|
120
120
|
// hydrates in the browser, so importing the build-time payload here would
|
|
121
121
|
// ship the whole catalog twice.
|
|
122
122
|
export default function Catalog({ packages, vscodeExtension, }) {
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
|
|
123
|
+
// Empty on the first render, ALWAYS — `?q=…` is applied a beat later, in
|
|
124
|
+
// the layout effect below. This is not a style preference, it is the one
|
|
125
|
+
// rule this island has to obey.
|
|
126
|
+
//
|
|
127
|
+
// Preact does not diff props while hydrating; its own source says so, and
|
|
128
|
+
// only re-applies props whose value is a function. Text children *are*
|
|
129
|
+
// diffed. So when the first client render disagrees with the server's, you
|
|
130
|
+
// get cards whose text is right and whose every attribute belongs to
|
|
131
|
+
// whichever package the server put at that position: one package's logo
|
|
132
|
+
// over another's name, and a link that opens the wrong page. Nothing
|
|
133
|
+
// throws. This used to seed from `location` here, and did exactly that.
|
|
134
|
+
const [query, setQuery] = useState("");
|
|
135
|
+
// Whether the URL's query has been applied. Gates the reveal below, so the
|
|
136
|
+
// catalog is never unhidden while it still shows the unfiltered list.
|
|
137
|
+
const [seeded, setSeeded] = useState(false);
|
|
129
138
|
const [kind, setKind] = useState(null);
|
|
130
139
|
const [sort, setSort] = useState("name");
|
|
131
140
|
// Deprecated packages are hidden until asked for: a retired package is
|
|
@@ -168,19 +177,29 @@ export default function Catalog({ packages, vscodeExtension, }) {
|
|
|
168
177
|
behavior: matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth",
|
|
169
178
|
});
|
|
170
179
|
};
|
|
180
|
+
// Apply `?q=…`, now that hydration has matched the server's markup and
|
|
181
|
+
// Preact owns the tree. A layout effect rather than a plain one: the
|
|
182
|
+
// resulting render must land before the browser paints, or a `?q=` visitor
|
|
183
|
+
// sees the whole catalog flash past on the way to their results.
|
|
184
|
+
useLayoutEffect(() => {
|
|
185
|
+
setQuery(new URLSearchParams(location.search).get("q") ?? "");
|
|
186
|
+
setSeeded(true);
|
|
187
|
+
}, []);
|
|
171
188
|
// Base.astro hides the catalog before first paint when the URL carries a
|
|
172
|
-
// query. Reveal it once
|
|
173
|
-
//
|
|
189
|
+
// query. Reveal it only once the filtered render is in the DOM — keyed on
|
|
190
|
+
// `seeded`, so the unfiltered first render is never the one revealed.
|
|
174
191
|
useLayoutEffect(() => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
//
|
|
178
|
-
//
|
|
192
|
+
if (!seeded)
|
|
193
|
+
return;
|
|
194
|
+
// The input's `value` prop was skipped during hydration for the same
|
|
195
|
+
// reason every other prop was, and the render that applied the query is
|
|
196
|
+
// a normal diff — but write it anyway: this effect is also what runs on
|
|
197
|
+
// a `?q=`-less load, where no second render is queued at all.
|
|
179
198
|
const input = searchRef.current;
|
|
180
199
|
if (input && input.value !== query)
|
|
181
200
|
input.value = query;
|
|
182
201
|
delete document.documentElement.dataset.query;
|
|
183
|
-
}, []);
|
|
202
|
+
}, [seeded]);
|
|
184
203
|
// `/` jumps to the search box, the convention every package registry
|
|
185
204
|
// shares. Bound on the document so it works wherever the reader is.
|
|
186
205
|
useEffect(() => {
|
|
@@ -187,14 +187,21 @@ export default function Catalog({
|
|
|
187
187
|
packages: CatalogPackage[];
|
|
188
188
|
vscodeExtension: string | null;
|
|
189
189
|
}) {
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
190
|
+
// Empty on the first render, ALWAYS — `?q=…` is applied a beat later, in
|
|
191
|
+
// the layout effect below. This is not a style preference, it is the one
|
|
192
|
+
// rule this island has to obey.
|
|
193
|
+
//
|
|
194
|
+
// Preact does not diff props while hydrating; its own source says so, and
|
|
195
|
+
// only re-applies props whose value is a function. Text children *are*
|
|
196
|
+
// diffed. So when the first client render disagrees with the server's, you
|
|
197
|
+
// get cards whose text is right and whose every attribute belongs to
|
|
198
|
+
// whichever package the server put at that position: one package's logo
|
|
199
|
+
// over another's name, and a link that opens the wrong page. Nothing
|
|
200
|
+
// throws. This used to seed from `location` here, and did exactly that.
|
|
201
|
+
const [query, setQuery] = useState("");
|
|
202
|
+
// Whether the URL's query has been applied. Gates the reveal below, so the
|
|
203
|
+
// catalog is never unhidden while it still shows the unfiltered list.
|
|
204
|
+
const [seeded, setSeeded] = useState(false);
|
|
198
205
|
const [kind, setKind] = useState<string | null>(null);
|
|
199
206
|
const [sort, setSort] = useState<Sort>("name");
|
|
200
207
|
// Deprecated packages are hidden until asked for: a retired package is
|
|
@@ -240,18 +247,28 @@ export default function Catalog({
|
|
|
240
247
|
});
|
|
241
248
|
};
|
|
242
249
|
|
|
250
|
+
// Apply `?q=…`, now that hydration has matched the server's markup and
|
|
251
|
+
// Preact owns the tree. A layout effect rather than a plain one: the
|
|
252
|
+
// resulting render must land before the browser paints, or a `?q=` visitor
|
|
253
|
+
// sees the whole catalog flash past on the way to their results.
|
|
254
|
+
useLayoutEffect(() => {
|
|
255
|
+
setQuery(new URLSearchParams(location.search).get("q") ?? "");
|
|
256
|
+
setSeeded(true);
|
|
257
|
+
}, []);
|
|
258
|
+
|
|
243
259
|
// Base.astro hides the catalog before first paint when the URL carries a
|
|
244
|
-
// query. Reveal it once
|
|
245
|
-
//
|
|
260
|
+
// query. Reveal it only once the filtered render is in the DOM — keyed on
|
|
261
|
+
// `seeded`, so the unfiltered first render is never the one revealed.
|
|
246
262
|
useLayoutEffect(() => {
|
|
247
|
-
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
263
|
+
if (!seeded) return;
|
|
264
|
+
// The input's `value` prop was skipped during hydration for the same
|
|
265
|
+
// reason every other prop was, and the render that applied the query is
|
|
266
|
+
// a normal diff — but write it anyway: this effect is also what runs on
|
|
267
|
+
// a `?q=`-less load, where no second render is queued at all.
|
|
251
268
|
const input = searchRef.current;
|
|
252
269
|
if (input && input.value !== query) input.value = query;
|
|
253
270
|
delete document.documentElement.dataset.query;
|
|
254
|
-
}, []);
|
|
271
|
+
}, [seeded]);
|
|
255
272
|
|
|
256
273
|
// `/` jumps to the search box, the convention every package registry
|
|
257
274
|
// shares. Bound on the document so it works wherever the reader is.
|
|
@@ -68,9 +68,10 @@ function repoLabel(url: string): string {
|
|
|
68
68
|
// package page) means the catalog the server rendered — every package,
|
|
69
69
|
// empty search box — is the wrong one. Flag it so CSS holds the
|
|
70
70
|
// catalog back rather than showing the full list and collapsing it a
|
|
71
|
-
// moment later. The island drops the flag
|
|
72
|
-
// is
|
|
73
|
-
//
|
|
71
|
+
// moment later. The island drops the flag once it has applied the
|
|
72
|
+
// query — which is the render after hydration, never the hydrating one
|
|
73
|
+
// itself; the timeout is the failsafe for an island that never
|
|
74
|
+
// hydrates, where a flash beats a blank page.
|
|
74
75
|
if (new URLSearchParams(location.search).get("q")) {
|
|
75
76
|
document.documentElement.dataset.query = "";
|
|
76
77
|
setTimeout(() => delete document.documentElement.dataset.query, 3000);
|
|
@@ -167,6 +168,18 @@ function repoLabel(url: string): string {
|
|
|
167
168
|
config.footerNote ? ` · ${config.footerNote}` : ""
|
|
168
169
|
}
|
|
169
170
|
</p>
|
|
171
|
+
{/* Whatever this index has to link — a privacy notice, an imprint, a
|
|
172
|
+
code of conduct. Absent by default, so a footer without them looks
|
|
173
|
+
exactly as it did before. */}
|
|
174
|
+
{
|
|
175
|
+
config.footerLinks.length > 0 && (
|
|
176
|
+
<p class="footer-links">
|
|
177
|
+
{config.footerLinks.map((link) => (
|
|
178
|
+
<a href={link.href}>{link.label}</a>
|
|
179
|
+
))}
|
|
180
|
+
</p>
|
|
181
|
+
)
|
|
182
|
+
}
|
|
170
183
|
{/* Opt-out, not opt-in: an index runner who does not want to say
|
|
171
184
|
where the software came from sets `attribution: false`, and this
|
|
172
185
|
disappears. Nothing else on the page changes.
|
|
@@ -788,6 +801,14 @@ function repoLabel(url: string): string {
|
|
|
788
801
|
.attribution span[aria-hidden] {
|
|
789
802
|
color: var(--accent);
|
|
790
803
|
}
|
|
804
|
+
/* Sits between the raw-data line and the attribution, which keeps its
|
|
805
|
+
`margin-inline-start: auto` and so stays pinned to the end. */
|
|
806
|
+
.footer-links {
|
|
807
|
+
margin: 0;
|
|
808
|
+
display: flex;
|
|
809
|
+
flex-wrap: wrap;
|
|
810
|
+
gap: 0.35rem 1rem;
|
|
811
|
+
}
|
|
791
812
|
|
|
792
813
|
/* Copy toast. Fixed and centred at the bottom: a card's three copy
|
|
793
814
|
buttons sit a few pixels apart and all flash the same check, so
|
|
@@ -844,8 +865,10 @@ function repoLabel(url: string): string {
|
|
|
844
865
|
search box, so painting it and then collapsing to the match is a
|
|
845
866
|
flash of the wrong answer. `visibility` rather than `display` —
|
|
846
867
|
the space stays reserved, so the footer does not jump either. The
|
|
847
|
-
attribute is set before first paint and dropped
|
|
848
|
-
|
|
868
|
+
attribute is set before first paint and dropped once the island
|
|
869
|
+
has applied the query — the render after hydration, because
|
|
870
|
+
hydrating against markup that disagrees with the server silently
|
|
871
|
+
mismatches every attribute (see Catalog.tsx). */
|
|
849
872
|
:root[data-query] .catalog {
|
|
850
873
|
visibility: hidden;
|
|
851
874
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grimoire-rs/indexer",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "CLI + Astro integration for running your own grim package index",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"@vitest/coverage-v8": "^4.1.10",
|
|
39
39
|
"eslint": "^10.8.0",
|
|
40
40
|
"js-yaml": "^4.1.0",
|
|
41
|
+
"jsdom": "^29.1.1",
|
|
41
42
|
"typescript": "^6.0.3",
|
|
42
43
|
"typescript-eslint": "^8.65.0",
|
|
43
44
|
"vitest": "^4.1.10"
|