npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@paulperigault/guards

v0.1.0

Published

Garde-fous de conception : tailles, couleurs, couches, tokens, images, config ESLint.

Readme

@paulperigault/guards

Contrôles de conception et d'architecture du design system, sans dépendance d'exécution.

Installation

npm i -D @paulperigault/guards

Commande

pp-guards <contrôle> [options] [racines…]

Contrôles : tokens, design, size, layers, architecture, images, et all.

Codes de sortie : 0 (succès), 1 (problèmes détectés), 2 (usage ou configuration).

Les racines à parcourir sont des positionnels : pp-guards design src apps. Elles remplacent la clé roots du fichier de configuration. Chaque contrôle accepte aussi --config <fichier> (défaut : pp-guards.config.json) et --help.

Ordre de priorité des options : défauts du contrôle, section du fichier de configuration, drapeaux, puis positionnels pour les racines. Un tableau remplace le précédent, il ne s'y ajoute pas.

tokens

Vérifie que chaque var(--pp-…) désigne un token de tokens.json ou une propriété --pp-* déclarée dans les sources scannées. Une référence inconnue est une erreur (code 1). Les tokens jamais utilisés sont signalés par un avertissement qui ne change pas le code de sortie. Ce contrôle ne cherche pas les valeurs brutes : c'est le rôle de design.

Fichiers scannés : .astro, .css, .ts, .mjs, hors node_modules, dist et generated.

pp-guards tokens --tokens node_modules/@paulperigault/tokens/generated/tokens.json src
  • --tokens <chemin> : fichier tokens.json (obligatoire, clé tokens de la section)
  • au moins une racine, en positionnel ou par roots dans la configuration

Sans l'un des deux, le contrôle s'arrête avec le code 2.

design

Applique les interdits « anti-IA » d'AGENTS.md.

pp-guards design [options] [racines…]
  • --roots <dossier> (répétable) : racines, autre forme des positionnels (défaut : src)
  • --extensions <ext> (répétable) : défaut .astro, .css, .html, .md, .mdx, .jsx, .tsx
  • --allow <chemin> (répétable) : exempte le chemin de toutes les règles
  • --disable <règle> (répétable) : désactive une règle partout

Règles : gradient, shadow, blur, emoji, spaced-caps, tailwind-palette, arbitrary-value, color-literal, retro-effect, generic-phrase, physical-property. Un identifiant inconnu dans --disable ou dans allow[].rules donne le code 2.

Portée selon l'extension :

  • .css et blocs <style> : déclarations CSS (dégradés, ombres, flou, color-literal, retro-effect, majuscules espacées, physical-property)
  • .astro, .html, .jsx, .tsx : attributs class, className, class:list (classes utilitaires) en plus des blocs <style>
  • tous les fichiers, .md et .mdx compris : emoji et generic-phrase

physical-property refuse les déclarations physiques (margin-left, width, top, border-right, overflow-x, text-align: left…) au profit des propriétés logiques (margin-inline-start, inline-size, inset-block-start…), qui suivent le sens d'écriture. Les conditions @media et @container ne sont pas visées. Dans les attributs class, la règle vise les utilitaires Tailwind physiques de l'axe en ligne (ml-*, pr-*, left-*, text-left, rounded-l-*, border-r-*, float-right…), qui ont un équivalent logique (ms-*, pe-*, start-*, text-start, rounded-s-*, border-e-*) ; l'axe de bloc (mt-*, mb-*) reste permis.

color-literal vise les valeurs CSS : notations hexadécimales, fonctions de couleur (rgb(), oklch()…) et noms de couleur dans les propriétés de couleur. La police mono n'est pas visée : l'ADR-0002 la permet pour le code, les identifiants, les empreintes et les journaux.

Les listes exactes (phrases génériques, couleurs nommées, motifs de classes) sont dans src/domain/design/*.ts.

Dans le fichier de configuration, allow accepte aussi des objets, que la ligne de commande ne sait pas exprimer :

{
  "path": "packages/tokens/generated",
  "rules": ["color-literal"],
  "reason": "tokens.css est généré depuis la source DTCG"
}
  • path (obligatoire) : chemin POSIX exempté
  • rules (facultatif) : règles exemptées, toutes si absent
  • reason (facultatif) : justification

size

Refuse les fichiers qui dépassent un nombre de lignes. Un saut de ligne final n'est pas compté.

pp-guards size [options] [racines…]
  • --max <nombre> : entier positif (défaut : 120)
  • --ext <ext> (répétable) : défaut .ts, .astro, .css, .mjs (clé extensions en configuration)

Racines par défaut : src.

layers

Vérifie le sens des imports entre couches. Les couches sont listées de la plus basse à la plus haute ; un fichier ne peut pas importer une couche plus haute que la sienne. Une couche a :

  • name : identifiant unique
  • paths : dossiers de la couche (obligatoire, non vide)
  • packages : noms de paquets npm qui désignent la couche (facultatif)

Un import relatif est rattaché à une couche par son chemin, un import de paquet par packages. Si aucun fichier scanné n'appartient à une couche, le contrôle échoue : layers[].paths est probablement faux.

pp-guards layers [racines…]

Pas de drapeau propre : la liste layers se règle dans la configuration. Les clés roots (défaut : .) et extensions (défaut : .ts, .mjs, .js, .astro, .css) sont facultatives.

architecture

Vérifie la règle de dépendance vers l'intérieur d'un paquet (ADR-0006, décision 1). Sous chaque racine de roots (par exemple packages/guards/src), les dossiers directs sont des anneaux, listés du plus interne au plus externe (défaut : domain, application, infrastructure).

  • Un import relatif ne va jamais vers un anneau plus externe, même pour un type.
  • Seul l'anneau le plus externe importe node:* et des paquets. Les anneaux internes permettent pureNode (défaut : node:path, node:buffer, node:util, sans entrée-sortie), allowPackages (défaut : aucun) et tout import type.
  • Un fichier hors anneau (index.ts, errors.ts) n'est pas contrôlé et reste importable partout.
  • Si aucun fichier scanné n'appartient à un anneau, le contrôle échoue : roots ou rings est probablement faux.
pp-guards architecture [racines…]

Pas de drapeau propre : roots, rings, pureNode, allowPackages et extensions (défaut : .ts) se règlent dans la configuration.

images

pp-guards images [options] [racines…]
  • --allow <chemin> (répétable) : où le balisage brut est permis (défaut : src/media)
  • --maxKb <nombre> : budget par fichier, en Ko (défaut : 500, 1 Ko = 1024 octets)
  • --budgets <json> : budgets par chemin, par exemple '[{"path":"public/hero","maxKb":800}]'

Racines par défaut : src et public. Trois vérifications :

  • Balisage : <img> brut (.astro, .html, .md, .mdx, .jsx, .tsx) et background ou background-image avec url( (.css, .astro) sont refusés hors de allow. <Image>, <Picture> et le src: url() d'une police ne sont pas visés.
  • Métadonnées : les JPEG et PNG qui contiennent des données EXIF, GPS ou XMP sont refusés. Le message propose exiftool -all= -overwrite_original "<fichier>". Les autres formats ne sont pas analysés.
  • Poids : .jpg, .jpeg, .png, .webp, .avif, .gif et .svg ne dépassent pas maxKb. Dans budgets, l'entrée dont le path est le plus long l'emporte sur maxKb.

all

pp-guards all [--config <fichier>]

Exécute dans l'ordre tokens, design, size, layers, architecture, images, mais seulement ceux dont la section existe dans la configuration. Le code de sortie est le plus élevé des codes obtenus. Aucune section : code 2. Les positionnels et les autres drapeaux ne sont pas acceptés.

Configuration

Fichier par défaut : pp-guards.config.json à la racine du projet. Une clé par contrôle, avec les mêmes noms que les drapeaux (maxKb, budgets, allow…) et roots pour les racines.

{
  "tokens": {
    "tokens": "packages/tokens/generated/tokens.json",
    "roots": ["packages/css/src", "packages/astro/src"]
  },
  "design": { "roots": ["packages", "apps"] },
  "size": { "roots": ["packages", "apps"], "max": 120 },
  "layers": {
    "layers": [
      { "name": "tokens", "paths": ["packages/tokens/src"], "packages": ["@paulperigault/tokens"] },
      { "name": "css", "paths": ["packages/css/src"], "packages": ["@paulperigault/css"] }
    ]
  },
  "architecture": { "roots": ["packages/guards/src"] },
  "images": { "roots": ["packages", "apps"], "allow": ["src/media"], "maxKb": 500 }
}

Branchement dans verify

Un script guard lance tous les contrôles, et verify l'appelle, comme dans le site généré par @paulperigault/create :

{
  "scripts": {
    "guard": "pp-guards all",
    "verify": "npm run guard && astro build"
  }
}

Configuration ESLint

Les seuils de conception (fonction de 40 lignes au plus, complexité 8, profondeur 3, 4 paramètres, 3 callbacks imbriqués, pas de nombre magique) sont exportés pour ESLint. Le sous-chemin @paulperigault/guards/eslint dépend d'un export déclaré dans package.json par l'orchestrateur.

// eslint.config.mjs
import tseslint from 'typescript-eslint';
import { designConfig } from '@paulperigault/guards/eslint';

export default tseslint.config(...tseslint.configs.recommended, ...designConfig());
  • designRules : objet de règles, à fusionner dans une configuration existante
  • testRelaxations : règles désactivées pour les tests (max-lines-per-function, max-nested-callbacks, @typescript-eslint/no-magic-numbers)
  • designConfig({ testFiles }) : tableau de deux éléments de configuration plate, designRules puis testRelaxations limité à testFiles (défaut : **/*.test.{ts,mjs,js}, **/test/**/*.ts, **/e2e/**/*.ts)

La règle @typescript-eslint/no-magic-numbers demande que le greffon typescript-eslint soit chargé par le projet : ce paquet n'a aucune dépendance d'exécution.