Aller au contenu

Générateur de Générateur Nx

Ajoute un Nx Generator à un projet TypeScript pour vous aider à automatiser des tâches répétitives comme la création de composants ou l’application de structures de projet spécifiques.

Utilisation

Générer un générateur

Vous pouvez générer un générateur de deux manières :

  1. Installez le Nx Console VSCode Plugin si ce n'est pas déjà fait
  2. Ouvrez la console Nx dans VSCode
  3. Cliquez sur Generate (UI) dans la section "Common Nx Commands"
  4. Recherchez @aws/nx-plugin - ts#nx-generator
  5. Remplissez les paramètres requis
    • Cliquez sur Generate

    Options

    Paramètre Type Par défaut Description
    pluginProject Requis string - TypeScript project to add the generator to. We recommend creating a ts#project in a top-level 'tools' directory.
    name Requis string - Generator name
    description string - A description of your generator
    directory string - The directory within the plugin project's source folder to add the generator to (default: <name>)

    Résultat du générateur

    Le générateur créera les fichiers suivants dans le pluginProject spécifié :

    • Répertoiresrc/<name>/
      • schema.json Schéma pour les entrées de votre générateur
      • schema.d.ts Types TypeScript pour votre schéma
      • generator.ts Implémentation de base du générateur
      • generator.spec.ts Tests pour votre générateur
    • generators.json Configuration Nx pour définir vos générateurs
    • package.json Créé ou mis à jour pour ajouter une entrée “generators”
    • tsconfig.json Mis à jour pour utiliser CommonJS

    Ce générateur mettra à jour le pluginProject sélectionné pour utiliser CommonJS, car les générateurs Nx ne prennent actuellement en charge que CommonJS (voir cette issue GitHub pour le support ESM).

    Générateurs locaux

    Sélectionnez votre projet local nx-plugin lors de l’exécution du générateur ts#nx-generator, puis spécifiez un nom ainsi qu’un répertoire et une description optionnels.

    Définition du schéma

    Le fichier schema.json définit les options acceptées par votre générateur. Il suit le format JSON Schema avec des extensions spécifiques à Nx.

    Structure de base

    Un fichier schema.json a la structure de base suivante :

    {
    "$schema": "https://json-schema.org/schema",
    "$id": "YourGeneratorName",
    "title": "Your Generator Title",
    "description": "Description of what your generator does",
    "type": "object",
    "properties": {
    // Vos options de générateur ici
    },
    "required": ["requiredOption1", "requiredOption2"]
    }

    Exemple simple

    Voici un exemple simple avec quelques options basiques :

    {
    "$schema": "https://json-schema.org/schema",
    "$id": "ComponentGenerator",
    "title": "Create a Component",
    "description": "Creates a new React component",
    "type": "object",
    "properties": {
    "name": {
    "type": "string",
    "description": "Component name",
    "x-priority": "important"
    },
    "directory": {
    "type": "string",
    "description": "Directory where the component will be created",
    "default": "src/components"
    },
    "withTests": {
    "type": "boolean",
    "description": "Whether to generate test files",
    "default": true
    }
    },
    "required": ["name"]
    }

    Invites interactives (CLI)

    Vous pouvez personnaliser les invites affichées lors de l’exécution de votre générateur via la CLI en ajoutant la propriété x-prompt :

    "name": {
    "type": "string",
    "description": "Component name",
    "x-prompt": "What is the name of your component?"
    }

    Pour les options booléennes, utilisez une invite oui/non :

    "withTests": {
    "type": "boolean",
    "description": "Whether to generate test files",
    "x-prompt": "Would you like to generate test files?"
    }

    Sélections déroulantes

    Pour les options avec un ensemble fixe de choix, utilisez enum pour permettre aux utilisateurs de sélectionner une option.

    "style": {
    "type": "string",
    "description": "The styling approach to use",
    "enum": ["css", "scss", "styled-components", "none"],
    "default": "css"
    }

    Liste déroulante de sélection de projet

    Un modèle courant consiste à laisser les utilisateurs sélectionner parmi les projets existants :

    "project": {
    "type": "string",
    "description": "The project to add the component to",
    "x-prompt": "Which project would you like to add the component to?",
    "x-dropdown": "projects"
    }

    La propriété x-dropdown: "projects" indique à Nx de peupler la liste avec tous les projets de l’espace de travail.

    Arguments positionnels

    Vous pouvez configurer des options à passer comme arguments positionnels via la ligne de commande :

    "name": {
    "type": "string",
    "description": "Component name",
    "x-priority": "important",
    "$default": {
    "$source": "argv",
    "index": 0
    }
    }

    Cela permet d’exécuter le générateur comme nx g your-generator my-component au lieu de nx g your-generator --name=my-component.

    Définition des priorités

    Utilisez la propriété x-priority pour indiquer les options les plus importantes :

    "name": {
    "type": "string",
    "description": "Component name",
    "x-priority": "important"
    }

    Les priorités peuvent être "important" ou "internal". Cela aide Nx à ordonner les propriétés dans l’extension VSCode et la CLI.

    Valeurs par défaut

    Vous pouvez fournir des valeurs par défaut :

    "directory": {
    "type": "string",
    "description": "Directory where the component will be created",
    "default": "src/components"
    }

    Plus d’informations

    Pour plus de détails sur les schémas, consultez la documentation Nx sur les options de générateur.

    Types TypeScript avec schema.d.ts

    En plus de schema.json, le générateur crée un fichier schema.d.ts fournissant des types TypeScript pour vos options :

    export interface YourGeneratorSchema {
    name: string;
    directory?: string;
    withTests?: boolean;
    }

    Cette interface est utilisée dans votre implémentation pour la sécurité des types et l’autocomplétion :

    import { YourGeneratorSchema } from './schema';
    export default async function (tree: Tree, options: YourGeneratorSchema) {
    // TypeScript connaît les types de toutes vos options
    const { name, directory = 'src/components', withTests = true } = options;
    // ...
    }

    Implémentation d’un générateur

    Après avoir créé le générateur, vous pouvez écrire son implémentation dans generator.ts.

    Un générateur est une fonction qui modifie un système de fichiers virtuel (Tree), lisant et écrivant des fichiers pour effectuer les changements. Les modifications ne sont écrites sur le disque qu’après l’exécution du générateur, sauf en mode “dry-run”.

    Voici des opérations courantes dans un générateur :

    Lecture et écriture de fichiers

    // Lire un fichier
    const content = tree.read('path/to/file.ts', 'utf-8');
    // Écrire un fichier
    tree.write('path/to/new-file.ts', 'export const hello = "world";');
    // Vérifier l'existence d'un fichier
    if (tree.exists('path/to/file.ts')) {
    // Faire quelque chose
    }

    Génération de fichiers à partir de modèles

    Utilisez generateFiles de @nx/devkit pour générer des fichiers avec des modèles EJS.

    import { generateFiles, joinPathFragments } from '@nx/devkit';
    // Générer des fichiers à partir de modèles
    generateFiles(
    tree,
    joinPathFragments(__dirname, 'files'), // Répertoire des modèles
    'path/to/output', // Répertoire de sortie
    {
    // Variables de substitution
    name: options.name,
    nameCamelCase: camelCase(options.name),
    nameKebabCase: kebabCase(options.name),
    },
    );

    Manipulation d’AST TypeScript

    Utilisez tsAstReplace du plugin Nx pour AWS pour modifier l’AST TypeScript :

    import { tsAstReplace } from '@aws/nx-plugin/sdk/utils/ast';
    import * as ts from 'typescript';
    // Exemple : Incrémenter un numéro de version
    tsAstReplace(
    tree,
    'path/to/version.ts',
    'VariableDeclaration:has(Identifier[name="VERSION"]) NumericLiteral',
    (node: ts.NumericLiteral) =>
    ts.factory.createNumericLiteral(Number(node.text) + 1));

    Ajout de dépendances

    import { addDependenciesToPackageJson } from '@nx/devkit';
    // Ajouter des dépendances à package.json
    addDependenciesToPackageJson(
    tree,
    {
    'new-dependency': '^1.0.0',
    },
    {
    'new-dev-dependency': '^2.0.0',
    },
    );

    Formatage des fichiers générés

    import { formatFilesInSubtree } from '@aws/nx-plugin/sdk/utils/format';
    // Formater tous les fichiers modifiés
    await formatFilesInSubtree(tree, 'optional/path/to/format');

    Lecture et mise à jour de fichiers JSON

    import { readJson, updateJson } from '@nx/devkit';
    // Lire un fichier JSON
    const packageJson = readJson(tree, 'package.json');
    // Mettre à jour un fichier JSON
    updateJson(tree, 'tsconfig.json', (json) => {
    json.compilerOptions = {
    ...json.compilerOptions,
    strict: true,
    };
    return json;
    });

    Extension d’un générateur du plugin Nx pour AWS

    Vous pouvez importer et étendre des générateurs existants :

    import { tsProjectGenerator } from '@aws/nx-plugin/sdk/ts';
    export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => {
    const callback = await tsProjectGenerator(tree, { ... });
    // Étendre le générateur de projet TypeScript ici
    return callback;
    };

    Générateurs OpenAPI

    Vous pouvez utiliser les générateurs pour les clients TypeScript et les hooks :

    import { openApiTsClientGenerator } from '@aws/nx-plugin/sdk/open-api';
    export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => {
    await openApiTsClientGenerator(tree, { ... });
    // Ajouter des fichiers supplémentaires ici
    };

    Nous exposons aussi une méthode pour générer des structures de données à partir de spécifications OpenAPI :

    import { buildOpenApiCodeGenerationData } from '@aws/nx-plugin/sdk/open-api.js';
    export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => {
    const data = await buildOpenApiCodeGenerationData(tree, 'path/to/spec.json');
    generateFiles(
    tree,
    joinPathFragments(__dirname, 'files'),
    'path/to/output',
    data,
    );
    };

    Exemple de template EJS :

    files/my-operations.ts.template
    export const myOperationNames = [
    <%_ allOperations.forEach((op) => { _%>
    '<%- op.name %>',
    <%_ }); _%>
    ];

    Consultez le dépôt GitHub pour des exemples complexes.

    Exécution de votre générateur

    Deux méthodes pour exécuter votre générateur :

    1. Installez le Nx Console VSCode Plugin si ce n'est pas déjà fait
    2. Ouvrez la console Nx dans VSCode
    3. Cliquez sur Generate (UI) dans la section "Common Nx Commands"
    4. Recherchez @my-project/nx-plugin - my-generator
    5. Remplissez les paramètres requis
      • Cliquez sur Generate

      Tests de votre générateur

      Les tests unitaires suivent ce modèle :

      import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
      import { yourGenerator } from './generator';
      describe('your generator', () => {
      let tree;
      beforeEach(() => {
      tree = createTreeWithEmptyWorkspace();
      tree.write('src/existing-file.ts', 'export const existing = true;');
      });
      it('should generate expected files', async () => {
      await yourGenerator(tree, { name: 'test' });
      expect(tree.exists('src/test/file.ts')).toBeTruthy();
      expect(tree.read('src/test/file.ts', 'utf-8')).toMatchSnapshot();
      });
      it('should handle errors', async () => {
      await expect(yourGenerator(tree, { name: 'invalid' }))
      .rejects.toThrow('Expected error message');
      });
      });

      Points clés pour les tests :

      • Utilisez createTreeWithEmptyWorkspace() pour un système de fichiers virtuel
      • Testez la création de fichiers et les mises à jour
      • Utilisez des snapshots pour le contenu complexe
      • Testez les cas d’erreur

      Contribution de générateurs à @aws/nx-plugin

      Le générateur ts#nx-generator peut aussi scaffold un générateur dans @aws/nx-plugin.

      Dans notre dépôt, il génèrera :

      • Répertoirepackages/nx-plugin/src/<name>/
        • schema.json Schéma d’entrée
        • schema.d.ts Types TypeScript
        • generator.ts Implémentation
        • generator.spec.ts Tests
      • Répertoiredocs/src/content/docs/guides/
        • <name>.mdx Page de documentation
      • packages/nx-plugin/generators.json Mis à jour