Vous pouvez créer vos propres schematics pour agir sur des projets Angular. Les développeurs de libraries incluent généralement des schematics dans leurs libraries pour les intégrer à l'Angular CLI. Vous pouvez aussi créer des schematics autonomes pour manipuler les fichiers et les structures des applications Angular, afin de les adapter à votre environnement de développement et de les rendre conformes à vos standards et à vos contraintes. Les schematics peuvent être chaînés, en exécutant d'autres schematics pour réaliser des opérations complexes.
Manipuler le code d'une application peut s'avérer à la fois très puissant et, en conséquence, dangereux. Par exemple, créer un fichier qui existe déjà serait une erreur et, si l'opération était appliquée immédiatement, elle annulerait toutes les autres modifications appliquées jusque-là. L'outillage Angular Schematics protège contre les effets de bord et les erreurs en créant un système de fichiers virtuel. Un schematic décrit un pipeline de transformations qui peuvent être appliquées au système de fichiers virtuel. Lorsqu'un schematic s'exécute, les transformations sont enregistrées en mémoire, et ne sont appliquées au système de fichiers réel qu'une fois leur validité confirmée.
Concepts des schematics
L'API publique des schematics définit des classes qui représentent les concepts de base.
Le système de fichiers virtuel est représenté par un
Tree. La structure de donnéesTreecontient une base (un ensemble de fichiers qui existent déjà) et une zone de préparation (staging area : une liste de modifications à appliquer à la base). Lorsque vous effectuez des modifications, vous ne changez pas réellement la base : vous ajoutez ces modifications à la zone de préparation.Un objet
Ruledéfinit une fonction qui prend unTree, applique des transformations et renvoie un nouveauTree. Le fichier principal d'un schematic,index.ts, définit un ensemble de règles qui implémentent la logique du schematic.Une transformation est représentée par une
Action. Il existe quatre types d'actions :Create,Rename,OverwriteetDelete.Chaque schematic s'exécute dans un contexte, représenté par un objet
SchematicContext.
L'objet de contexte passé à une règle donne accès à des fonctions utilitaires et aux métadonnées dont le schematic peut avoir besoin, notamment une API de journalisation pour faciliter le débogage. Le contexte définit aussi une stratégie de fusion qui détermine comment les modifications sont fusionnées depuis l'arbre de préparation vers l'arbre de base. Une modification peut être acceptée, ignorée, ou lever une exception.
Définir des règles et des actions
Lorsque vous créez un nouveau schematic vierge avec la CLI Schematics, la fonction d'entrée générée est une fabrique de règles.
Un objet RuleFactory définit une fonction d'ordre supérieur qui crée une Rule.
index.ts
import {Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
// You don't have to export the function as default.
// You can also have more than one rule factory per file.
export function helloWorld(_options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
return tree;
};
}
Vos règles peuvent modifier vos projets en appelant des outils externes et en implémentant de la logique. Vous avez par exemple besoin d'une règle pour définir comment un template du schematic doit être fusionné dans le projet hôte.
Les règles peuvent utiliser les utilitaires fournis avec le package @schematics/angular.
Recherchez les fonctions utilitaires pour manipuler les modules, les dépendances, TypeScript, l'AST, le JSON, les workspaces et projets Angular CLI, et plus encore.
index.ts
import {
JsonAstObject,
JsonObject,
JsonValue,
Path,
normalize,
parseJsonAst,
strings,
} from '@angular-devkit/core';
Définir les options d'entrée avec un schéma et des interfaces
Les règles peuvent récupérer des valeurs d'options auprès de l'appelant et les injecter dans des templates.
Les options disponibles pour vos règles, avec leurs valeurs autorisées et leurs valeurs par défaut, sont définies dans le fichier de schéma JSON du schematic, <schematic>/schema.json.
Définissez les types de données variables ou énumérés du schéma à l'aide d'interfaces TypeScript.
Le schéma définit les types et les valeurs par défaut des variables utilisées dans le schematic. Par exemple, l'hypothétique schematic « Hello World » pourrait avoir le schéma suivant.
schema.json
{
"properties": {
"name": {
"type": "string",
"minLength": 1,
"default": "world"
},
"useColor": {
"type": "boolean"
}
}
}
Consultez des exemples de fichiers de schéma pour les schematics des commandes de l'Angular CLI dans @schematics/angular.
Prompts de schematic
Les prompts de schematic introduisent une interaction avec l'utilisateur dans l'exécution d'un schematic. Configurez les options du schematic pour afficher une question personnalisable à l'utilisateur. Les prompts sont affichés avant l'exécution du schematic, qui utilise ensuite la réponse comme valeur de l'option. Cela permet aux utilisateurs d'orienter le fonctionnement du schematic sans avoir besoin de connaître en détail tout l'éventail des options disponibles.
Le schematic « Hello World » pourrait par exemple demander son nom à l'utilisateur, puis afficher ce nom à la place du nom par défaut « world ».
Pour définir un tel prompt, ajoutez une propriété x-prompt au schéma de la variable name.
De même, vous pouvez ajouter un prompt pour laisser l'utilisateur décider si le schematic utilise la couleur lors de l'exécution de son action hello. Le schéma avec les deux prompts serait le suivant.
schema.json
{
"properties": {
"name": {
"type": "string",
"minLength": 1,
"default": "world",
"x-prompt": "What is your name?"
},
"useColor": {
"type": "boolean",
"x-prompt": "Would you like the response in color?"
}
}
}
Syntaxe courte des prompts
Ces exemples utilisent une forme abrégée de la syntaxe des prompts, qui ne fournit que le texte de la question.
Dans la plupart des cas, c'est tout ce qui est nécessaire.
Remarquez cependant que les deux prompts attendent des types d'entrée différents.
Avec la forme abrégée, le type le plus approprié est sélectionné automatiquement en fonction du schéma de la propriété.
Dans l'exemple, le prompt name utilise le type input parce qu'il s'agit d'une propriété de type chaîne.
Le prompt useColor utilise un type confirmation parce qu'il s'agit d'une propriété booléenne.
Dans ce cas, « yes » correspond à true et « no » correspond à false.
Trois types d'entrée sont pris en charge.
| Type d'entrée | Détails |
|---|---|
| confirmation | Une question à répondre par oui ou non ; idéal pour les options booléennes. |
| input | Saisie de texte ; idéal pour les options de type chaîne ou nombre. |
| list | Un ensemble prédéfini de valeurs autorisées. |
Dans la forme courte, le type est déduit du type et des contraintes de la propriété.
| Schéma de la propriété | Type de prompt |
|---|---|
| "type": "boolean" | confirmation ("yes"=true, "no"=false) |
| "type": "string" | input |
| "type": "number" | input (seuls les nombres valides sont acceptés) |
| "type": "integer" | input (seuls les nombres valides sont acceptés) |
| "enum": […] | list (les membres de l'enum deviennent les choix de la liste) |
Dans l'exemple suivant, la propriété prend une valeur énumérée : le schematic choisit donc automatiquement le type list et crée un menu à partir des valeurs possibles.
schema.json
{
"style": {
"description": "The file extension or preprocessor to use for style files.",
"type": "string",
"default": "css",
"enum": ["css", "scss", "sass", "less", "styl"],
"x-prompt": "Which stylesheet format would you like to use?"
}
}
Le runtime des prompts valide automatiquement la réponse fournie par rapport aux contraintes définies dans le schéma JSON. Si la valeur n'est pas acceptable, une nouvelle valeur est demandée à l'utilisateur. Cela garantit que toutes les valeurs passées au schematic répondent aux attentes de son implémentation, sans que vous ayez à ajouter de vérifications supplémentaires dans le code du schematic.
Syntaxe longue des prompts
La syntaxe du champ x-prompt prend en charge une forme longue pour les cas où vous avez besoin de davantage de personnalisation et de contrôle sur le prompt.
Dans cette forme, la valeur du champ x-prompt est un objet JSON dont les sous-champs personnalisent le comportement du prompt.
| Champ | Valeur |
|---|---|
| type | confirmation, input ou list (sélectionné automatiquement dans la forme courte) |
| message | chaîne (obligatoire) |
| items | chaîne et/ou paire label/value sous forme d'objet (valide uniquement avec le type list) |
L'exemple suivant de forme longue provient du schéma JSON du schematic que la CLI utilise pour générer des applications. Il définit le prompt qui permet aux utilisateurs de choisir le préprocesseur de styles à utiliser pour l'application en cours de création. Grâce à la forme longue, le schematic peut formater plus explicitement les choix du menu.
schema.json
{
"style": {
"description": "The file extension or preprocessor to use for style files.",
"type": "string",
"default": "css",
"enum": ["css", "scss", "sass", "less"],
"x-prompt": {
"message": "Which stylesheet format would you like to use?",
"type": "list",
"items": [
{"value": "css", "label": "CSS"},
{"value": "scss", "label": "SCSS [ https://sass-lang.com/documentation/syntax#scss ]"},
{
"value": "sass",
"label": "Sass [ https://sass-lang.com/documentation/syntax#the-indented-syntax ]"
},
{"value": "less", "label": "Less [ https://lesscss.org/ ]"}
]
}
}
}
Schéma x-prompt
Le schéma JSON qui définit les options d'un schematic prend en charge des extensions permettant de définir de manière déclarative les prompts et leur comportement respectif.
Aucune logique supplémentaire ni modification du code d'un schematic n'est nécessaire pour prendre en charge les prompts.
Le schéma JSON suivant décrit complètement la syntaxe longue du champ x-prompt.
x-prompt schema
{
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"type": {
"type": "string"
},
"message": {
"type": "string"
},
"items": {
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"label": {
"type": "string"
},
"value": {}
},
"required": ["value"]
}
]
}
}
},
"required": ["message"]
}
]
}
CLI Schematics
Les schematics disposent de leur propre outil en ligne de commande. Installez l'outil en ligne de commande Schematics globalement :
npm install -g @angular-devkit/schematics-cli
Cela installe l'exécutable schematics, que vous pouvez utiliser pour créer une nouvelle collection de schematics dans son propre dossier de projet, ajouter un nouveau schematic à une collection existante ou étendre un schematic existant.
Dans les sections suivantes, vous allez créer une nouvelle collection de schematics à l'aide de la CLI afin de découvrir les fichiers, la structure des fichiers et quelques concepts de base.
L'usage le plus courant des schematics reste toutefois l'intégration d'une library Angular à l'Angular CLI. Pour cela, créez les fichiers du schematic directement dans le projet de la library, au sein d'un workspace Angular, sans utiliser la CLI Schematics. Consultez Schematics pour les libraries.
Créer une collection de schematics
La commande suivante crée un nouveau schematic nommé hello-world dans un nouveau dossier de projet du même nom.
schematics blank --name=hello-world
Le schematic blank est fourni par la CLI Schematics.
La commande crée un nouveau dossier de projet (le dossier racine de la collection) et un premier schematic nommé dans la collection.
Allez dans le dossier de la collection, installez vos dépendances npm et ouvrez votre nouvelle collection dans votre éditeur favori pour voir les fichiers générés. Par exemple, si vous utilisez VS Code :
cd hello-world
npm install
npm run build
code .
Le schematic initial reçoit le même nom que le dossier du projet et est généré dans src/hello-world.
Ajoutez des schematics liés à cette collection et modifiez le code squelette généré pour définir les fonctionnalités de votre schematic.
Chaque nom de schematic doit être unique au sein de la collection.
Exécuter un schematic
Utilisez la commande schematics pour exécuter un schematic nommé.
Indiquez le chemin du dossier du projet, le nom du schematic et les options obligatoires, au format suivant.
schematics <path-to-schematics-project>:<schematics-name> --<required-option>=<value>
Le chemin peut être absolu ou relatif au répertoire de travail courant dans lequel la commande est exécutée. Par exemple, pour exécuter le schematic que vous venez de générer (qui n'a pas d'option obligatoire), utilisez la commande suivante.
schematics .:hello-world
Ajouter un schematic à une collection
Pour ajouter un schematic à une collection existante, utilisez la même commande que pour démarrer un nouveau projet de schematics, mais exécutez-la dans le dossier du projet.
cd hello-world
schematics blank --name=goodbye-world
La commande génère le nouveau schematic nommé dans votre collection, avec un fichier principal index.ts et son fichier de spec de test associé.
Elle ajoute aussi le nom, la description et la fonction de fabrique du nouveau schematic au schéma de la collection, dans le fichier collection.json.
Contenu d'une collection
Le niveau supérieur du dossier racine du projet d'une collection contient des fichiers de configuration, un dossier node_modules et un dossier src/.
Le dossier src/ contient des sous-dossiers pour les schematics nommés de la collection, ainsi qu'un schéma, collection.json, qui décrit les schematics regroupés.
Chaque schematic est créé avec un nom, une description et une fonction de fabrique.
{
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"hello-world": {
"description": "A blank schematic.",
"factory": "./hello-world/index#helloWorld"
}
}
}
La propriété
$schemaindique le schéma que la CLI utilise pour la validation.La propriété
schematicsliste les schematics nommés qui appartiennent à cette collection. Chaque schematic possède une description en texte brut et pointe vers la fonction d'entrée générée dans le fichier principal.La propriété
factorypointe vers la fonction d'entrée générée. Dans cet exemple, vous invoquez le schematichello-worlden appelant la fonction de fabriquehelloWorld().La propriété facultative
schemapointe vers un fichier de schéma JSON qui définit les options de ligne de commande disponibles pour le schematic.Le tableau facultatif
aliasesindique une ou plusieurs chaînes qui peuvent être utilisées pour invoquer le schematic. Par exemple, le schematic de la commande « generate » de l'Angular CLI a un alias « g », qui vous permet d'utiliser la commandeng g.
Schematics nommés
Lorsque vous utilisez la CLI Schematics pour créer un projet de schematics vierge, le nouveau schematic vierge est le premier membre de la collection et porte le même nom que celle-ci.
Lorsque vous ajoutez un nouveau schematic nommé à cette collection, il est automatiquement ajouté au schéma collection.json.
En plus du nom et de la description, chaque schematic possède une propriété factory qui identifie son point d'entrée.
Dans l'exemple, vous invoquez la fonctionnalité définie par le schematic en appelant la fonction helloWorld() dans le fichier principal, hello-world/index.ts.

Chaque schematic nommé de la collection comporte les parties principales suivantes.
| Parties | Détails |
|---|---|
index.ts |
Code qui définit la logique de transformation d'un schematic nommé. |
schema.json |
Définition des variables du schematic. |
schema.d.ts |
Variables du schematic. |
files/ |
Fichiers de composants/templates facultatifs à répliquer. |
Un schematic peut fournir toute sa logique dans le fichier index.ts, sans templates supplémentaires.
Vous pouvez toutefois créer des schematics dynamiques pour Angular en fournissant des composants et des templates dans le dossier files, comme ceux des projets Angular standalone.
La logique du fichier index configure ces templates en définissant des règles qui injectent des données et modifient des variables.