Перейти к содержанию

Создание авторских схем

📅 28.02.2022

Вы можете создавать собственные схемы для работы с проектами Angular. Разработчики библиотек обычно упаковывают схемы со своими библиотеками, чтобы интегрировать их с Angular CLI.

Вы также можете создавать отдельные схемы для работы с файлами и конструкциями в приложениях Angular, чтобы адаптировать их к своей среде разработки и сделать их соответствующими вашим стандартам и ограничениям.

Схемы можно объединять в цепочки, запуская другие схемы для выполнения сложных операций.

Манипулирование кодом в приложении может быть как очень мощным, так и соответственно опасным. Например, создание файла, который уже существует, будет ошибкой, а если его применить немедленно, то это приведет к отмене всех других изменений, примененных до сих пор.

Инструментарий Angular Schematics защищает от побочных эффектов и ошибок путем создания виртуальной файловой системы.

Схема описывает конвейер преобразований, которые могут быть применены к виртуальной файловой системе.

Когда схема выполняется, преобразования записываются в память и применяются к реальной файловой системе только после подтверждения их правильности.

Концепции схем

Публичный API для схем определяет классы, которые представляют основные концепции.

  • Виртуальная файловая система представлена в виде дерева. Структура данных Tree содержит базу (набор файлов, которые уже существуют) и область постановки (список изменений, которые будут применены к базе).

    При внесении изменений вы не изменяете базу, а добавляете эти изменения в область постановки.

  • Объект Rule определяет функцию, которая принимает Tree, применяет преобразования и возвращает новое Tree.

    Главный файл схемы, index.ts, определяет набор правил, которые реализуют логику схемы.

  • Преобразование представлено Action.

    Существует четыре типа действий: Create, Rename, Overwrite и Delete.

  • Каждая схема работает в контексте, представленном объектом SchematicContext.

Объект контекста, передаваемый в правило, предоставляет доступ к вспомогательным функциям и метаданным, которые могут понадобиться схеме для работы, включая API протоколирования для помощи в отладке. Контекст также определяет стратегию слияния, которая определяет, как изменения сливаются из поэтапного дерева в базовое дерево.

Изменение может быть принято или проигнорировано, или выбросить исключение.

Определение правил и действий

Когда вы создаете новую пустую схему с помощью Schematics CLI, сгенерированная функция ввода является фабрикой правил. Объект RuleFactory определяет функцию высшего порядка, которая создает Rule.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
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;
    };
}

Ваши правила могут вносить изменения в проекты, вызывая внешние инструменты и реализуя логику. Например, вам нужно правило, чтобы определить, как шаблон схемы должен быть объединен в проект хостинга.

Правила могут использовать утилиты, поставляемые с пакетом @schematics/angular. Ищите вспомогательные функции для работы с модулями, зависимостями, TypeScript, AST, JSON, рабочими пространствами и проектами Angular CLI и многое другое.

1
2
3
4
5
6
7
8
9
import {
    JsonAstObject,
    JsonObject,
    JsonValue,
    Path,
    normalize,
    parseJsonAst,
    strings,
} from '@angular-devkit/core';

Определение входных опций с помощью схемы и интерфейсов

Правила могут собирать значения опций от вызывающей стороны и вводить их в шаблоны. Опции, доступные для ваших правил, с их допустимыми значениями и значениями по умолчанию, определяются в файле схемы JSON схемы схемы, <schematic>/schema.json.

Определите переменные или перечислимые типы данных для схемы с помощью интерфейсов TypeScript.

Схема определяет типы и значения по умолчанию переменных, используемых в схеме. Например, гипотетическая схема "Hello World" может иметь следующую схему.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
    "properties": {
        "name": {
            "type": "string",
            "minLength": 1,
            "default": "world"
        },
        "useColor": {
            "type": "boolean"
        }
    }
}

Смотрите примеры файлов схем для схем команд Angular CLI в @schematics/angular.

Схематические подсказки

Схематические подсказки вводят взаимодействие с пользователем при выполнении схемы. Настройте параметры схемы для отображения настраиваемого вопроса пользователю.

Подсказки отображаются перед выполнением схемы, которая затем использует ответ в качестве значения для опции.

Это позволяет пользователям управлять работой схемы, не требуя глубокого знания всего спектра доступных опций.

Например, схема "Hello World" может попросить пользователя назвать свое имя и отобразить его вместо стандартного имени "world". Чтобы определить такую подсказку, добавьте в схему свойство x-prompt для переменной name.

Аналогично можно добавить подсказку, позволяющую пользователю решить, будет ли схема использовать цвет при выполнении действия hello. Схема с обеими подсказками будет выглядеть следующим образом.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
    "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?"
        }
    }
}

Синтаксис краткой формы подсказки

В этих примерах используется сокращенная форма синтаксиса подсказки, в которой задается только текст вопроса. В большинстве случаев это все, что требуется.

Заметьте, однако, что эти две подсказки ожидают разных типов ввода.

При использовании сокращенной формы наиболее подходящий тип выбирается автоматически на основе схемы свойства.

В примере подсказка name использует тип input, поскольку это строковое свойство.

Подсказка useColor использует тип confirmation, поскольку является булевым свойством.

В данном случае "да" соответствует true, а "нет" — false.

Существует три поддерживаемых типа ввода.

Тип ввода Подробности
confirmation Вопрос "да" или "нет"; идеально подходит для булевых опций.
input Текстовый ввод; идеально подходит для строковых или числовых опций.
list Предопределенный набор допустимых значений.

В краткой форме тип выводится из типа свойства и ограничений.

Схема свойства Тип подсказки
"type": "boolean" confirmation ("yes"=true, "no"=false)
"type": "string" input
"type": "number" input (принимаются только допустимые числа)
"type": "integer" input (принимаются только действительные числа)
"enum": [...] list (члены перечисления становятся выборками списка)

В следующем примере свойство принимает перечислимое значение, поэтому схема автоматически выбирает тип списка и создает меню из возможных значений.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
"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?"
}

Время выполнения подсказки автоматически проверяет предоставленный ответ на соответствие ограничениям, указанным в схеме JSON. Если значение неприемлемо, пользователю предлагается ввести новое значение.

Это гарантирует, что любые значения, передаваемые схеме, соответствуют ожиданиям реализации схемы, поэтому вам не нужно добавлять дополнительные проверки в код схемы.

Синтаксис длинной формы Prompt

Синтаксис поля x-prompt поддерживает длинную форму для случаев, когда требуется дополнительная настройка и контроль над подсказкой. В этой форме значение поля x-prompt представляет собой объект JSON с подполями, которые настраивают поведение подсказки.

Поле Значение данных
type confirmation, input или list (выбирается автоматически в короткой форме)
message строка (требуется)
items строка и/или пара метка/значение объекта (только для типа list)

Следующий пример длинной формы взят из схемы JSON для схемы, которую CLI использует для генерации приложений. Он определяет подсказку, позволяющую пользователям выбрать, какой препроцессор стиля они хотят использовать для создаваемого приложения.

Используя длинную форму, схема может обеспечить более явное форматирование вариантов меню.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
"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/]" }
    ],
  },
},

x-prompt schema

JSON-схема, определяющая опции схемы, поддерживает расширения, позволяющие декларативно определять подсказки и их соответствующее поведение. Никакой дополнительной логики или изменений в коде схемы для поддержки подсказок не требуется.

Следующая схема JSON представляет собой полное описание синтаксиса длинной формы для поля x-prompt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
    "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"]
        }
    ]
}

Schematics CLI

Schematics поставляется с собственным инструментом командной строки. Используя Node 6.9 или более позднюю версию, установите инструмент командной строки Schematics глобально:

1
npm install -g @angular-devkit/schematics-cli

Это устанавливает исполняемый файл schematics, который можно использовать для создания новой коллекции схем в собственной папке проекта, добавления новой схемы в существующую коллекцию или расширения существующей схемы.

В следующих разделах вы создадите новую коллекцию схем с помощью CLI, чтобы ознакомиться с файлами и структурой файлов, а также с некоторыми основными понятиями.

Однако наиболее распространенное использование схем — это интеграция библиотеки Angular с Angular CLI. Для этого нужно создать файлы схем непосредственно в проекте библиотеки в рабочем пространстве Angular, не используя Schematics CLI.

Смотрите Schematics for Libraries.

Создание коллекции схем

Следующая команда создает новую схему с именем hello-world в новой папке проекта с тем же именем.

1
schematics blank --name=hello-world

Схема blank предоставляется Schematics CLI. Команда создает новую папку проекта (корневая папка для коллекции) и первоначальную схему в коллекции.

Перейдите в папку коллекции, установите зависимости npm и откройте новую коллекцию в вашем любимом редакторе, чтобы увидеть сгенерированные файлы. Например, если вы используете VS Code:

1
2
3
4
cd hello-world
npm install
npm run build
code .

Начальная схема получает то же имя, что и папка проекта, и генерируется в src/hello-world. Добавьте связанные схемы в эту коллекцию и измените сгенерированный скелетный код, чтобы определить функциональность вашей схемы.

Имя каждой схемы должно быть уникальным в пределах коллекции.

Запуск схемы

Используйте команду chematics для запуска именованной схемы. Укажите путь к папке проекта, имя схемы и все обязательные опции в следующем формате.

1
schematics <path-to-schematics-project>:<schematics-name> --<required-option>=<value>

Путь может быть абсолютным или относительным к текущему рабочему каталогу, в котором выполняется команда. Например, чтобы запустить только что созданную схему (которая не имеет необходимых опций), используйте следующую команду.

1
schematics .:hello-world

Добавление схемы в коллекцию

Чтобы добавить схему в существующую коллекцию, используйте ту же команду, которую вы используете для запуска нового проекта schematics, но запустите команду внутри папки проекта.

1
2
cd hello-world
schematics blank --name=goodbye-world

Команда создает новую именованную схему внутри вашей коллекции, с основным файлом index.ts и связанной с ним тестовой спецификацией. Она также добавляет имя, описание и фабричную функцию для новой схемы в схему коллекции в файле collection.json.

Содержимое коллекции

Верхний уровень корневой папки проекта для коллекции содержит файлы конфигурации, папку node_modules и папку src/. Папка src/ содержит вложенные папки для именованных схем коллекции и схему collection.json, которая описывает собранные схемы.

Каждая схема создается с именем, описанием и заводской функцией.

1
2
3
4
5
6
7
8
9
{
    "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
    "schematics": {
        "hello-world": {
            "description": "A blank schematic.",
            "factory": "./hello-world/index#helloWorld"
        }
    }
}
  • Свойство $schema указывает схему, которую CLI использует для проверки.
  • Свойство schematics перечисляет именованные схемы, принадлежащие данной коллекции.

    Каждая схема имеет текстовое описание и указывает на сгенерированную функцию ввода в главном файле.

  • Свойство factory указывает на сгенерированную функцию входа.

    В этом примере вы вызываете схему hello-world, вызывая фабричную функцию helloWorld().

  • Необязательное свойство chema указывает на файл схемы JSON, определяющий опции командной строки, доступные для схемы.

  • Необязательный массив aliases указывает одну или несколько строк, которые могут быть использованы для вызова схемы.

    Например, схема для команды Angular CLI "generate" имеет псевдоним "g", который позволяет использовать команду ng g.

Именованные схемы

Когда вы используете Schematics CLI для создания пустого проекта схемы, новая пустая схема является первым членом коллекции и имеет то же имя, что и коллекция. Когда вы добавляете новую схему с именем в эту коллекцию, она автоматически добавляется в схему collection.json.

Помимо имени и описания, каждая схема имеет свойство factory, которое идентифицирует точку входа схемы. В примере вы вызываете определенную функциональность схемы, вызывая функцию helloWorld() в главном файле hello-world/index.ts.

overview

Каждая именованная схема в коллекции имеет следующие основные части.

Parts Details
index.ts Код, определяющий логику преобразования для именованной схемы.
schema.json Определение переменной схемы.
schema.d.ts Переменные схемы.
files/ Необязательные файлы компонентов/шаблонов для репликации.

Схема может содержать всю свою логику в файле index.ts, без дополнительных шаблонов. Однако вы можете создавать динамические схемы для Angular, предоставляя компоненты и шаблоны в папке files, как в отдельных проектах Angular.

Логика в индексном файле настраивает эти шаблоны, определяя правила, которые вводят данные и изменяют переменные.

Ссылки

Комментарии