416 lines
11 KiB
TypeScript
416 lines
11 KiB
TypeScript
import type { CollectionEntry } from "astro:content";
|
|
|
|
export type GlossaryEntry = CollectionEntry<"glossaire">;
|
|
|
|
export const GLOSSARY_COLLATOR = new Intl.Collator("fr", {
|
|
sensitivity: "base",
|
|
numeric: true,
|
|
});
|
|
|
|
export const FAMILY_LABELS: Record<string, string> = {
|
|
"concept-fondamental": "Concept fondamental",
|
|
scene: "Scène",
|
|
dynamique: "Dynamique",
|
|
pathologie: "Pathologie",
|
|
topologie: "Topologie",
|
|
"meta-regime": "Méta-régime",
|
|
paradigme: "Paradigme",
|
|
doctrine: "Doctrine",
|
|
verbe: "Verbe",
|
|
"dispositif-ia": "Dispositif IA",
|
|
"tension-irreductible": "Tension irréductible",
|
|
figure: "Figure",
|
|
qualification: "Qualification",
|
|
epistemologie: "Épistémologie",
|
|
};
|
|
|
|
export const KIND_LABELS: Record<string, string> = {
|
|
concept: "Concept",
|
|
diagnostic: "Diagnostic",
|
|
topologie: "Topologie",
|
|
verbe: "Verbe",
|
|
paradigme: "Paradigme",
|
|
doctrine: "Doctrine",
|
|
dispositif: "Dispositif",
|
|
figure: "Figure",
|
|
qualification: "Qualification",
|
|
epistemologie: "Épistémologie",
|
|
};
|
|
|
|
export const DOMAIN_LABELS: Record<string, string> = {
|
|
transversal: "Transversal",
|
|
theorie: "Théorie",
|
|
"cas-ia": "Cas IA",
|
|
};
|
|
|
|
export const LEVEL_LABELS: Record<string, string> = {
|
|
fondamental: "Fondamental",
|
|
intermediaire: "Intermédiaire",
|
|
avance: "Avancé",
|
|
};
|
|
|
|
export const FONDAMENTAUX_WANTED = [
|
|
"archicratie",
|
|
"arcalite",
|
|
"cratialite",
|
|
"archicration",
|
|
"co-viabilite",
|
|
"tension",
|
|
] as const;
|
|
|
|
export const FAMILY_SECTION_TITLES: Record<string, string> = {
|
|
"concept-fondamental": "Noyau archicratique",
|
|
scene: "Scènes archicratiques",
|
|
dynamique: "Dynamiques archicratiques",
|
|
pathologie: "Pathologies archicratiques",
|
|
topologie: "Topologies voisines",
|
|
"meta-regime": "Méta-régimes archicratiques",
|
|
paradigme: "Paradigmes voisins",
|
|
doctrine: "Doctrines fondatrices",
|
|
verbe: "Verbes de la scène",
|
|
"dispositif-ia": "Dispositifs IA",
|
|
"tension-irreductible": "Tensions irréductibles",
|
|
figure: "Figures archicratiques",
|
|
qualification: "Qualifications archicratiques",
|
|
epistemologie: "Outillage épistémologique",
|
|
};
|
|
|
|
export function normalizeGlossarySlug(value: unknown): string {
|
|
return String(value ?? "")
|
|
.trim()
|
|
.replace(/^\/+|\/+$/g, "")
|
|
.replace(/\.(md|mdx)$/i, "")
|
|
.toLowerCase();
|
|
}
|
|
|
|
export function slugOfGlossaryEntry(
|
|
entry: Pick<GlossaryEntry, "id"> | null | undefined,
|
|
): string {
|
|
return normalizeGlossarySlug(entry?.id ?? "");
|
|
}
|
|
|
|
export function hrefOfGlossaryEntry(
|
|
entry: Pick<GlossaryEntry, "id"> | null | undefined,
|
|
): string {
|
|
const slug = slugOfGlossaryEntry(entry);
|
|
return slug ? `/glossaire/${slug}/` : "/glossaire/";
|
|
}
|
|
|
|
export function buildGlossaryBySlug(
|
|
entries: GlossaryEntry[] = [],
|
|
): Map<string, GlossaryEntry> {
|
|
return new Map(
|
|
entries.map((entry) => [slugOfGlossaryEntry(entry), entry]),
|
|
);
|
|
}
|
|
|
|
export function sortGlossaryEntries(
|
|
entries: GlossaryEntry[] = [],
|
|
): GlossaryEntry[] {
|
|
return [...entries].sort((a, b) =>
|
|
GLOSSARY_COLLATOR.compare(a.data.term, b.data.term),
|
|
);
|
|
}
|
|
|
|
export function uniqueGlossaryEntries(
|
|
entries: GlossaryEntry[] = [],
|
|
): GlossaryEntry[] {
|
|
const seen = new Set<string>();
|
|
const out: GlossaryEntry[] = [];
|
|
|
|
for (const entry of entries) {
|
|
const slug = slugOfGlossaryEntry(entry);
|
|
if (!slug || seen.has(slug)) continue;
|
|
seen.add(slug);
|
|
out.push(entry);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
export function resolveGlossaryEntriesInSourceOrder(
|
|
slugs: string[] = [],
|
|
allEntries: GlossaryEntry[] = [],
|
|
): GlossaryEntry[] {
|
|
const bySlug = buildGlossaryBySlug(allEntries);
|
|
const seen = new Set<string>();
|
|
const resolved: GlossaryEntry[] = [];
|
|
|
|
for (const rawSlug of slugs) {
|
|
const slug = normalizeGlossarySlug(rawSlug);
|
|
if (!slug || seen.has(slug)) continue;
|
|
|
|
const entry = bySlug.get(slug);
|
|
if (!entry) continue;
|
|
|
|
seen.add(slug);
|
|
resolved.push(entry);
|
|
}
|
|
|
|
return resolved;
|
|
}
|
|
|
|
export function resolveGlossaryEntries(
|
|
slugs: string[] = [],
|
|
allEntries: GlossaryEntry[] = [],
|
|
): GlossaryEntry[] {
|
|
return sortGlossaryEntries(
|
|
resolveGlossaryEntriesInSourceOrder(slugs, allEntries),
|
|
);
|
|
}
|
|
|
|
export function rawFamilyOf(
|
|
entry: GlossaryEntry | null | undefined,
|
|
): string {
|
|
return String(entry?.data?.family ?? "");
|
|
}
|
|
|
|
export function kindOf(
|
|
entry: GlossaryEntry | null | undefined,
|
|
): string {
|
|
return String(entry?.data?.kind ?? "");
|
|
}
|
|
|
|
export function familyOf(
|
|
entry: GlossaryEntry | null | undefined,
|
|
): string {
|
|
const explicit = rawFamilyOf(entry);
|
|
if (explicit) return explicit;
|
|
|
|
const slug = slugOfGlossaryEntry(entry);
|
|
const kind = kindOf(entry);
|
|
|
|
if (kind === "paradigme") return "paradigme";
|
|
if (kind === "doctrine") return "doctrine";
|
|
if (kind === "verbe") return "verbe";
|
|
|
|
if (slug === "scene-depreuve") return "scene";
|
|
if (slug === "autarchicratie") return "pathologie";
|
|
if (slug === "obliteration-archicratique") return "dynamique";
|
|
|
|
if (FONDAMENTAUX_WANTED.includes(slug as (typeof FONDAMENTAUX_WANTED)[number])) {
|
|
return "concept-fondamental";
|
|
}
|
|
|
|
if (slug === "archicrations-differentielles-et-formes-hybrides") {
|
|
return "topologie";
|
|
}
|
|
|
|
if (kind === "topologie" && slug.startsWith("archicrations-")) {
|
|
return "meta-regime";
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
export function getDisplayFamily(
|
|
entry: GlossaryEntry | null | undefined,
|
|
): string {
|
|
const familyKey = rawFamilyOf(entry) || familyOf(entry);
|
|
return FAMILY_LABELS[familyKey] ?? KIND_LABELS[kindOf(entry)] ?? "Fiche";
|
|
}
|
|
|
|
export function getDisplayDomain(
|
|
entry: GlossaryEntry | null | undefined,
|
|
): string {
|
|
const key = String(entry?.data?.domain ?? "");
|
|
return key ? (DOMAIN_LABELS[key] ?? key) : "";
|
|
}
|
|
|
|
export function getDisplayLevel(
|
|
entry: GlossaryEntry | null | undefined,
|
|
): string {
|
|
const key = String(entry?.data?.level ?? "");
|
|
return key ? (LEVEL_LABELS[key] ?? key) : "";
|
|
}
|
|
|
|
export function getFondamentaux(
|
|
entries: GlossaryEntry[] = [],
|
|
): GlossaryEntry[] {
|
|
const bySlug = buildGlossaryBySlug(entries);
|
|
|
|
return sortGlossaryEntries(
|
|
FONDAMENTAUX_WANTED
|
|
.map((slug) => bySlug.get(slug))
|
|
.filter(Boolean) as GlossaryEntry[],
|
|
);
|
|
}
|
|
|
|
export function getGlossaryEntriesByFamily(
|
|
entries: GlossaryEntry[] = [],
|
|
familyKey: string,
|
|
): GlossaryEntry[] {
|
|
return sortGlossaryEntries(
|
|
entries.filter((entry) => familyOf(entry) === familyKey),
|
|
);
|
|
}
|
|
|
|
export function countGlossaryEntriesByKind(
|
|
entries: GlossaryEntry[] = [],
|
|
kindKey: string,
|
|
): number {
|
|
return entries.filter((entry) => kindOf(entry) === kindKey).length;
|
|
}
|
|
|
|
export function countGlossaryEntriesByFamily(
|
|
entries: GlossaryEntry[] = [],
|
|
familyKey: string,
|
|
): number {
|
|
return entries.filter((entry) => familyOf(entry) === familyKey).length;
|
|
}
|
|
|
|
export function getEntriesOfSameFamily(
|
|
entry: GlossaryEntry,
|
|
allEntries: GlossaryEntry[] = [],
|
|
): GlossaryEntry[] {
|
|
const familyKey = familyOf(entry);
|
|
if (!familyKey) return [];
|
|
|
|
if (familyKey === "concept-fondamental") {
|
|
return getFondamentaux(allEntries);
|
|
}
|
|
|
|
return getGlossaryEntriesByFamily(allEntries, familyKey);
|
|
}
|
|
|
|
export function getSameFamilyTitle(
|
|
entry: GlossaryEntry,
|
|
): string {
|
|
return FAMILY_SECTION_TITLES[familyOf(entry)] ?? "Même famille";
|
|
}
|
|
|
|
export type GlossaryRelationBlock = {
|
|
title: string;
|
|
items: GlossaryEntry[];
|
|
className: string;
|
|
};
|
|
|
|
export function getRelationBlocks(
|
|
entry: GlossaryEntry,
|
|
allEntries: GlossaryEntry[] = [],
|
|
): GlossaryRelationBlock[] {
|
|
const currentSlug = slugOfGlossaryEntry(entry);
|
|
|
|
const relatedEntries = resolveGlossaryEntriesInSourceOrder(
|
|
entry.data.related ?? [],
|
|
allEntries,
|
|
).filter((item) => slugOfGlossaryEntry(item) !== currentSlug);
|
|
|
|
const opposedEntries = resolveGlossaryEntriesInSourceOrder(
|
|
entry.data.opposedTo ?? [],
|
|
allEntries,
|
|
).filter((item) => slugOfGlossaryEntry(item) !== currentSlug);
|
|
|
|
const seeAlsoEntries = resolveGlossaryEntriesInSourceOrder(
|
|
entry.data.seeAlso ?? [],
|
|
allEntries,
|
|
).filter((item) => slugOfGlossaryEntry(item) !== currentSlug);
|
|
|
|
return [
|
|
{
|
|
title: "Concepts liés",
|
|
items: relatedEntries,
|
|
className: "is-related",
|
|
},
|
|
{
|
|
title: "En tension avec",
|
|
items: opposedEntries,
|
|
className: "is-opposed",
|
|
},
|
|
{
|
|
title: "Voir aussi",
|
|
items: seeAlsoEntries,
|
|
className: "is-see-also",
|
|
},
|
|
].filter((block) => block.items.length > 0);
|
|
}
|
|
|
|
export function getRelationSections(
|
|
entry: GlossaryEntry,
|
|
allEntries: GlossaryEntry[] = [],
|
|
): Array<{ title: string; items: GlossaryEntry[] }> {
|
|
return getRelationBlocks(entry, allEntries).map(({ title, items }) => ({
|
|
title,
|
|
items,
|
|
}));
|
|
}
|
|
|
|
function isTheoryEntry(entry: GlossaryEntry): boolean {
|
|
const familyKey = familyOf(entry);
|
|
const kindKey = kindOf(entry);
|
|
|
|
return (
|
|
familyKey === "paradigme" ||
|
|
familyKey === "doctrine" ||
|
|
kindKey === "paradigme" ||
|
|
kindKey === "doctrine"
|
|
);
|
|
}
|
|
|
|
const PREFERRED_PARADIGME_SLUGS = [
|
|
"gouvernementalite",
|
|
"gouvernementalite-algorithmique",
|
|
"cybernetique",
|
|
"biopolitique",
|
|
"domination-legale-rationnelle",
|
|
"democratie-deliberative",
|
|
"gouvernance-des-communs",
|
|
"agencement-machinique",
|
|
"pharmacologie-technique",
|
|
"preemption-algorithmique",
|
|
"dissensus-politique",
|
|
"lieu-vide-du-pouvoir",
|
|
"habitus-et-violence-symbolique",
|
|
"theorie-de-la-resonance",
|
|
"conatus-et-multitude",
|
|
"configuration-et-interdependance",
|
|
"technodiversite-et-cosmotechnie",
|
|
"grammatisation-et-proletarisation-cognitive",
|
|
] as const;
|
|
|
|
const PREFERRED_DOCTRINE_SLUGS = [
|
|
"contractualisme-hobbesien",
|
|
"droit-naturel-et-propriete",
|
|
"volonte-generale",
|
|
"decisionnisme-souverain",
|
|
] as const;
|
|
|
|
export function getContextualTheory(
|
|
entry: GlossaryEntry,
|
|
allEntries: GlossaryEntry[] = [],
|
|
): GlossaryEntry[] {
|
|
const currentSlug = slugOfGlossaryEntry(entry);
|
|
const bySlug = buildGlossaryBySlug(allEntries);
|
|
|
|
const fromRelations = uniqueGlossaryEntries([
|
|
...resolveGlossaryEntries(entry.data.related ?? [], allEntries),
|
|
...resolveGlossaryEntries(entry.data.seeAlso ?? [], allEntries),
|
|
...resolveGlossaryEntries(entry.data.opposedTo ?? [], allEntries),
|
|
])
|
|
.filter((item) => slugOfGlossaryEntry(item) !== currentSlug)
|
|
.filter((item) => isTheoryEntry(item));
|
|
|
|
if (fromRelations.length > 0) {
|
|
return sortGlossaryEntries(fromRelations).slice(0, 6);
|
|
}
|
|
|
|
if (familyOf(entry) === "paradigme") {
|
|
return uniqueGlossaryEntries(
|
|
PREFERRED_PARADIGME_SLUGS
|
|
.filter((slug) => slug !== currentSlug)
|
|
.map((slug) => bySlug.get(slug))
|
|
.filter(Boolean) as GlossaryEntry[],
|
|
).slice(0, 8);
|
|
}
|
|
|
|
if (familyOf(entry) === "doctrine") {
|
|
return uniqueGlossaryEntries(
|
|
PREFERRED_DOCTRINE_SLUGS
|
|
.filter((slug) => slug !== currentSlug)
|
|
.map((slug) => bySlug.get(slug))
|
|
.filter(Boolean) as GlossaryEntry[],
|
|
).slice(0, 6);
|
|
}
|
|
|
|
return [];
|
|
} |