@nodefony/documentation 10.0.0-alpha.1
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/LICENSE +544 -0
- package/README.md +168 -0
- package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js +9 -0
- package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js +6 -0
- package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateParam.js +8 -0
- package/dist/index.js +75 -0
- package/dist/nodefony/config/config.js +71 -0
- package/dist/nodefony/config/defineModuleConfig.js +49 -0
- package/dist/nodefony/controller/DocumentationController.js +102 -0
- package/dist/nodefony/interfaces/IDocumentation.js +1 -0
- package/dist/nodefony/interfaces/index.js +1 -0
- package/dist/nodefony/service/DocumentationService.js +421 -0
- package/dist/nodefony/src/docScanner.js +58 -0
- package/dist/nodefony/src/errors/DocumentationError.js +45 -0
- package/dist/nodefony/src/frontmatter.js +63 -0
- package/dist/nodefony/src/linkResolver.js +68 -0
- package/dist/nodefony/src/search.js +120 -0
- package/dist/nodefony/src/slug.js +62 -0
- package/dist/types/index.d.ts +58 -0
- package/dist/types/nodefony/config/config.d.ts +37 -0
- package/dist/types/nodefony/config/defineModuleConfig.d.ts +17 -0
- package/dist/types/nodefony/controller/DocumentationController.d.ts +33 -0
- package/dist/types/nodefony/interfaces/IDocumentation.d.ts +144 -0
- package/dist/types/nodefony/interfaces/index.d.ts +5 -0
- package/dist/types/nodefony/service/DocumentationService.d.ts +78 -0
- package/dist/types/nodefony/src/docScanner.d.ts +47 -0
- package/dist/types/nodefony/src/errors/DocumentationError.d.ts +32 -0
- package/dist/types/nodefony/src/frontmatter.d.ts +37 -0
- package/dist/types/nodefony/src/linkResolver.d.ts +55 -0
- package/dist/types/nodefony/src/search.d.ts +64 -0
- package/dist/types/nodefony/src/slug.d.ts +48 -0
- package/docs/architecture.md +647 -0
- package/docs/index.md +369 -0
- package/package.json +81 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parseur de frontmatter YAML minimal — **sans dépendance**.
|
|
3
|
+
*
|
|
4
|
+
* Un fichier de doc Nodefony commence (optionnellement) par un bloc encadré de
|
|
5
|
+
* `---` qui porte des métadonnées (`title`, `audience`, `section`, `version`,
|
|
6
|
+
* `status`, `updated`, `source`, `publish`). On n'embarque PAS `gray-matter` (~plusieurs
|
|
7
|
+
* deps transitives) pour ça : la doc n'utilise qu'un sous-ensemble plat de YAML
|
|
8
|
+
* (clé: valeur scalaire ou liste). Ce parseur couvre ce sous-ensemble et reste
|
|
9
|
+
* volontairement strict/petit.
|
|
10
|
+
*
|
|
11
|
+
* Supporté :
|
|
12
|
+
* - `key: value` → string (quotes simples/doubles retirées)
|
|
13
|
+
* - `key: [a, b, c]` → string[] (liste inline)
|
|
14
|
+
* - `key:` puis lignes ` - x` → string[] (liste en bloc)
|
|
15
|
+
* - lignes vides / commentaires `#` ignorées
|
|
16
|
+
*
|
|
17
|
+
* NON supporté (volontaire) : objets imbriqués, multi-lignes `|`/`>`, ancres.
|
|
18
|
+
* La doc n'en a pas besoin → on ne paie pas la complexité.
|
|
19
|
+
*/
|
|
20
|
+
/** Métadonnées extraites du frontmatter — valeurs scalaires ou listes. */
|
|
21
|
+
export type Frontmatter = Record<string, string | string[]>;
|
|
22
|
+
/** Résultat du parse : `meta` (frontmatter) + `body` (markdown sans le bloc). */
|
|
23
|
+
export interface ParsedDoc {
|
|
24
|
+
meta: Frontmatter;
|
|
25
|
+
body: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Sépare le bloc frontmatter du corps markdown et parse les métadonnées.
|
|
29
|
+
*
|
|
30
|
+
* @param raw - contenu brut du fichier `.md`.
|
|
31
|
+
* @returns `{ meta, body }` — `meta` vide et `body = raw` s'il n'y a pas de bloc.
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseFrontmatter(raw: string): ParsedDoc;
|
|
34
|
+
/** Lit une clé de frontmatter en string (1er élément si liste), ou `undefined`. */
|
|
35
|
+
export declare function metaString(meta: Frontmatter, key: string): string | undefined;
|
|
36
|
+
/** Lit une clé de frontmatter en string[] (wrappe un scalaire), ou `[]`. */
|
|
37
|
+
export declare function metaList(meta: Frontmatter, key: string): string[];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Réécriture des liens internes d'une page de doc en **slugs**.
|
|
3
|
+
*
|
|
4
|
+
* Une page vit sur le disque et lie ses voisines par chemin relatif — c'est ce
|
|
5
|
+
* qui la rend lisible sur GitHub et dans un éditeur : `[CORS](cors.md)`,
|
|
6
|
+
* `[Documentation](../../../../../docs/index.md)`. Mais le portail ne navigue
|
|
7
|
+
* pas par chemin : il navigue par **slug** (`mod~security~cors`), parce qu'un
|
|
8
|
+
* slug est une clé d'allowlist et jamais un chemin FS (anti-traversée, cf
|
|
9
|
+
* {@link ../src/slug}).
|
|
10
|
+
*
|
|
11
|
+
* Sans traduction, seuls les liens PLATS fonctionnaient dans Studio : toute
|
|
12
|
+
* remontée (`../index.md`) tombait en ancre HTML morte. La résolution appartient
|
|
13
|
+
* au serveur, seul à connaître la table chemin → slug ; le client n'a aucun
|
|
14
|
+
* moyen de deviner à quel fichier `../../..` correspond.
|
|
15
|
+
*
|
|
16
|
+
* Le lien conserve l'extension `.md` après réécriture (`mod~security~cors.md`) :
|
|
17
|
+
* le rendu markdown reconnaît un lien interne à cette extension, et un slug
|
|
18
|
+
* seul serait indistinguable d'une URL relative quelconque.
|
|
19
|
+
*/
|
|
20
|
+
/** Options de {@link rewriteInternalLinks}. */
|
|
21
|
+
export interface RewriteLinksOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Dossier de la page courante, relatif à la racine du projet (POSIX, sans
|
|
24
|
+
* fichier). Ex. `src/packages/@nodefony/security/docs`.
|
|
25
|
+
*/
|
|
26
|
+
fromDir: string;
|
|
27
|
+
/**
|
|
28
|
+
* Traduit un chemin de fichier relatif à la racine du projet en slug.
|
|
29
|
+
* Retourne `undefined` si le fichier n'est pas dans l'index (lien laissé
|
|
30
|
+
* intact — on ne fabrique jamais un slug qui n'existe pas).
|
|
31
|
+
*/
|
|
32
|
+
toSlug: (repoRelPath: string) => string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Suffixe ajouté derrière la cible traduite. Vaut `".md"` par défaut : le
|
|
35
|
+
* portail reconnaît un lien interne à cette extension, et un slug nu serait
|
|
36
|
+
* indistinguable d'une URL relative quelconque.
|
|
37
|
+
*
|
|
38
|
+
* Un générateur de site statique publie en revanche des URL réelles
|
|
39
|
+
* (`/modules/security/cors/`) : il passe `""` et `toSlug` rend l'URL. Sans ce
|
|
40
|
+
* point d'extension, il faudrait recopier la résolution relative ailleurs —
|
|
41
|
+
* et deux implémentations d'une même règle divergent toujours.
|
|
42
|
+
*/
|
|
43
|
+
suffix?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Réécrit les liens markdown internes d'une page en slugs navigables.
|
|
47
|
+
*
|
|
48
|
+
* Un lien dont la cible n'est pas indexée est **laissé tel quel** : mieux vaut
|
|
49
|
+
* un lien inerte qu'un slug inventé qui produirait un 404 côté portail.
|
|
50
|
+
*
|
|
51
|
+
* @param markdown - corps de la page (frontmatter déjà retiré).
|
|
52
|
+
* @param options - dossier d'origine + résolution chemin → slug.
|
|
53
|
+
* @returns le markdown avec ses liens internes traduits.
|
|
54
|
+
*/
|
|
55
|
+
export declare function rewriteInternalLinks(markdown: string, options: RewriteLinksOptions): string;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recherche plein texte du corpus de documentation — brique PURE.
|
|
3
|
+
*
|
|
4
|
+
* Elle ne lit ni disque ni réseau : on lui passe des pages déjà chargées, elle
|
|
5
|
+
* rend un classement. C'est ce qui lui permet d'avoir DEUX consommateurs très
|
|
6
|
+
* différents sans être écrite deux fois :
|
|
7
|
+
*
|
|
8
|
+
* - le service {@link DocumentationService.search}, côté serveur, qui lit les
|
|
9
|
+
* `.md` du disque à chaque requête ;
|
|
10
|
+
* - le générateur du site public, qui n'a pas de serveur du tout : il embarque
|
|
11
|
+
* un index dans la page et fait tourner CETTE fonction dans le navigateur du
|
|
12
|
+
* lecteur (`searchDocs.toString()` — voir `build-docs-site.mjs`).
|
|
13
|
+
*
|
|
14
|
+
* D'où la contrainte qui gouverne ce fichier : **`searchDocs` et ses aides sont
|
|
15
|
+
* auto-suffisantes**. Aucun import, aucune variable de portée supérieure, aucune
|
|
16
|
+
* syntaxe qui suppose un bundler. Le jour où l'une d'elles capture quelque chose
|
|
17
|
+
* de son module, le site continue de se construire et la recherche casse chez le
|
|
18
|
+
* lecteur — sans un mot. Le test de parité (`search-parity.test.ts`) est là pour
|
|
19
|
+
* ça : il exécute la fonction SÉRIALISÉE, pas la fonction importée.
|
|
20
|
+
*/
|
|
21
|
+
import type { IDocSearchResult } from "../interfaces/IDocumentation.js";
|
|
22
|
+
/** Une page telle que la recherche a besoin de la voir. */
|
|
23
|
+
export interface SearchableDoc {
|
|
24
|
+
slug: string;
|
|
25
|
+
title: string;
|
|
26
|
+
navTitle: string;
|
|
27
|
+
/** Libellé de la section d'arbre qui porte la page (« Guides », « Cœur »…). */
|
|
28
|
+
sectionLabel: string;
|
|
29
|
+
/** Corps de la page, frontmatter retiré. */
|
|
30
|
+
body: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Réduit un texte à sa forme comparable : minuscules, accents retirés.
|
|
34
|
+
*
|
|
35
|
+
* « Sécurité » et « securite » doivent trouver la même chose — personne ne tape
|
|
36
|
+
* les accents dans un champ de recherche.
|
|
37
|
+
*/
|
|
38
|
+
export declare function foldText(text: string): string;
|
|
39
|
+
/** Termes effectivement cherchés : pliés, dédoublonnés, un caractère écarté. */
|
|
40
|
+
export declare function splitSearchTerms(query: string): string[];
|
|
41
|
+
/**
|
|
42
|
+
* Prose INDEXABLE d'une page de documentation.
|
|
43
|
+
*
|
|
44
|
+
* Ce qui est retiré ne l'est pas par souci de taille mais de PERTINENCE : un
|
|
45
|
+
* bloc de code fait remonter une page sur `const`, un tableau de compatibilité
|
|
46
|
+
* sur n'importe quel nom de navigateur, et le fil d'Ariane sur le titre de
|
|
47
|
+
* toutes ses voisines. Une recherche qui rend tout ne rend rien.
|
|
48
|
+
*
|
|
49
|
+
* @param markdown - le corps de la page, frontmatter déjà retiré.
|
|
50
|
+
* @returns le texte à indexer, lignes conservées (les extraits s'y resituent).
|
|
51
|
+
*/
|
|
52
|
+
export declare function extractSearchText(markdown: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* Classe les pages qui portent TOUS les termes, la plus pertinente d'abord.
|
|
55
|
+
*
|
|
56
|
+
* ⚠️ Cette fonction est SÉRIALISÉE et exécutée dans un navigateur (voir l'en-tête
|
|
57
|
+
* du fichier) : elle ne doit rien référencer hors de son propre corps.
|
|
58
|
+
*
|
|
59
|
+
* @param docs - le corpus à balayer.
|
|
60
|
+
* @param query - ce que le lecteur a tapé.
|
|
61
|
+
* @param limit - nombre de résultats rendus (le total retenu est dit à part).
|
|
62
|
+
* @returns le classement, plus ce que la recherche a réellement balayé.
|
|
63
|
+
*/
|
|
64
|
+
export declare function searchDocs(docs: SearchableDoc[], query: string, limit?: number): IDocSearchResult;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sécurité et encodage des slugs de documentation.
|
|
3
|
+
*
|
|
4
|
+
* Le data plane LIT des fichiers `.md` sur disque → surface de **traversée de
|
|
5
|
+
* répertoire** (path traversal). Règle de sécurité (cf
|
|
6
|
+
* `feedback_security_rfc_rigor`) :
|
|
7
|
+
*
|
|
8
|
+
* 1. Le slug n'est JAMAIS concaténé brut dans un chemin FS. Le service garde,
|
|
9
|
+
* pour chaque fichier scanné, son chemin absolu RÉEL ; servir une page =
|
|
10
|
+
* retrouver l'entrée par **égalité de slug** dans la liste scannée, puis
|
|
11
|
+
* lire le chemin connu. Le slug est une CLÉ d'allowlist, pas un chemin.
|
|
12
|
+
* 2. {@link isSafeSlug} est une garde **défense-en-profondeur** : on rejette
|
|
13
|
+
* tout slug suspect (segment `..`, séparateur de chemin, octet nul,
|
|
14
|
+
* caractère de contrôle) AVANT même de chercher dans l'allowlist.
|
|
15
|
+
*
|
|
16
|
+
* Schéma de slug (URL-safe, un seul segment de route) :
|
|
17
|
+
* - doc racine `docs/guides/session-storage.md` → `root~guides~session-storage`
|
|
18
|
+
* - doc module `<module>/docs/index.md` → `mod~<module>~index`
|
|
19
|
+
*
|
|
20
|
+
* Le `/` du chemin devient `~` (le slug doit tenir dans UN segment de route
|
|
21
|
+
* `/api/page/{slug}`). On NE reconstruit jamais le chemin depuis le slug.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Valide qu'un slug est sûr à manipuler (avant toute recherche/lecture).
|
|
25
|
+
*
|
|
26
|
+
* Rejette : chaîne vide, trop longue, segment `..`, présence de `/` `\` `\0`,
|
|
27
|
+
* tout caractère hors charset autorisé.
|
|
28
|
+
*
|
|
29
|
+
* @param slug - slug brut reçu du client (déjà URL-décodé par le framework).
|
|
30
|
+
* @returns `true` si le slug est sûr, `false` sinon.
|
|
31
|
+
*/
|
|
32
|
+
export declare function isSafeSlug(slug: string): boolean;
|
|
33
|
+
/** Source d'un fichier de doc : racine du projet ou un module. */
|
|
34
|
+
export type DocSource = {
|
|
35
|
+
kind: "root";
|
|
36
|
+
} | {
|
|
37
|
+
kind: "module";
|
|
38
|
+
module: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Construit le slug d'un fichier à partir de sa source et de son chemin
|
|
42
|
+
* relatif (POSIX, sans `.md`). Inverse jamais utilisé (slug = clé, pas chemin).
|
|
43
|
+
*
|
|
44
|
+
* @param source - racine ou module propriétaire.
|
|
45
|
+
* @param relPath - chemin relatif POSIX du `.md` (séparateur `/`).
|
|
46
|
+
* @returns slug URL-safe.
|
|
47
|
+
*/
|
|
48
|
+
export declare function pathToSlug(source: DocSource, relPath: string): string;
|