## @e22m4u/js-data-projection JavaScript модуль для работы с проекцией данных. Модуль использует схемы для определения правил видимости полей данных. Поддерживается вложенность, функции-фабрики, именованные схемы, области проекции и строгий режим. ## Содержание - [Установка](#установка) - [Использование](#использование) - [Создание проекции](#создание-проекции) - [Проекция массива](#проекция-массива) - [Строгий режим](#строгий-режим) - [Вложенные схемы](#вложенные-схемы) - [Область проекции](#область-проекции) - [Фабричные функции](#фабричные-функции) - [Именованные схемы](#именованные-схемы) - [Функция `projectData`](#функция-projectdata) - [Класс `DataProjector`](#класс-dataprojector) - [Метод `defineSchema`](#метод-defineschema) - [Метод `project`](#метод-project) - [Тесты](#тесты) - [Лицензия](#лицензия) ## Установка ```bash npm install @e22m4u/js-data-projection ``` ## Использование Модуль экспортирует функцию `projectData` для создания проекций и класс `DataProjector` с возможностью регистрации и применения именованных схем. #### Создание проекции Схема проекции описывает настройки видимости для каждого поля. Логические значения определяют видимость поля. Поля, отсутствующие в схеме, остаются в результате по умолчанию. ```js import {projectData} from '@e22m4u/js-data-projection'; const schema = { name: true, password: false, }; const data = { name: 'Fedor', // будет доступно, явное правило password: 'pass123', // будет исключено, явное правило extra: 10, // будет доступно в режиме по умолчанию }; const result = projectData(schema, data); console.log(result); // { // name: 'Fedor', // extra: 10 // } ``` #### Проекция массива Если входные данные представляют собой массив, то проекция применяется к каждому элементу рекурсивно. Структура результата соответствует исходному массиву. ```js import {projectData} from '@e22m4u/js-data-projection'; const schema = { id: true, secret: false, }; const data = [ {id: 1, secret: 'A'}, {id: 2, secret: 'B'}, ]; const result = projectData(schema, data); console.log(result); // [ // {id: 1}, // {id: 2} // ] ``` #### Строгий режим Строгий режим исключает из результата все поля, не описанные в схеме явно. Поведение регулируется опцией `strict`. Данный режим позволяет гарантировать отсутствие лишних данных в результате. ```js import {projectData} from '@e22m4u/js-data-projection'; const schema = { name: true, password: false, }; const data = { name: 'Fedor', // будет доступно, явное правило password: 'pass123', // будет исключено, явное правило extra: 10, // будет исключено в строгом режиме }; const result = projectData(schema, data, { strict: true, // <= строгий режим }); console.log(result); // { // name: 'Fedor' // } ``` #### Вложенные схемы Вложенные объекты обрабатываются с помощью свойства `schema` в настройках поля. Данное свойство позволяет определять правила видимости для вложенных структур данных. ```js import {projectData} from '@e22m4u/js-data-projection'; const schema = { id: false, name: true, city: { select: true, // правило видимости поля city schema: { // вложенная схема id: false, name: true, }, }, }; const data = { id: 10, // будет скрыто, явное правило name: 'Fedor', city: { id: 20, // будет скрыто, явное правило name: 'Moscow', }, }; const result = projectData(schema, data); console.log(result); // { // name: 'Fedor', // city: { // name: 'Moscow', // } // } ``` #### Область проекции Правила видимости полей могут зависеть от области проекции. Свойство `scopes` определяет специфичные правила для разных контекстов, передаваемых через опцию `scope`. ```js import {projectData} from '@e22m4u/js-data-projection'; const schema = { name: true, password: { scopes: { input: true, // правило для области 'input' output: false, // правило для области 'output' }, }, }; const data = { name: 'Fedor', // будет доступно, явное правило password: 'pass123', // будет доступно в зависимости от области }; const inputData = projectData(schema, data, { scope: 'input', // <= область проекции }); console.log(inputData); // { // name: 'Fedor', // password: 'pass123' // } const outputData = projectData(schema, data, { scope: 'output', // <= область проекции }); console.log(outputData); // { // name: 'Fedor' // } ``` Модуль экспортирует объект констант с именами часто используемых областей проекции. ```js import {ProjectionScope} from '@e22m4u/js-data-projection'; console.log(ProjectionScope); // { // INPUT: 'input', // OUTPUT: 'output' // } projectData(schema, data, { scope: ProjectionScope.INPUT, }); ``` #### Фабричные функции Вместо статической схемы можно передать фабричную функцию, которая вернет объект схемы. Это полезно, если схему необходимо генерировать динамически или переиспользовать логику создания схем. ```js import {projectData} from '@e22m4u/js-data-projection'; // фабрика возвращает объект схемы const getSchema = () => { return { id: true, hiddenField: false, }; }; const data = { id: 1, hiddenField: 'secret', }; // передача функции вместо объекта const result = projectData(getSchema, data); console.log(result); // { // id: 1 // } ``` Фабрики также поддерживаются во вложенных структурах. Свойство `schema` может принимать функцию, возвращающую схему для вложенного объекта. ```js import {projectData} from '@e22m4u/js-data-projection'; // фабрика для вложенных данных const getAddressSchema = () => ({ city: true, zip: false, }); const userSchema = { name: true, address: { schema: getAddressSchema, // <= использование фабрики }, }; const data = { name: 'Fedor', address: { city: 'Moscow', zip: 123456, }, }; const result = projectData(userSchema, data); console.log(result); // { // name: 'Fedor', // address: { // city: 'Moscow' // } // } ``` #### Именованные схемы Класс `DataProjector` позволяет сохранять схемы во внутреннем реестре для их последующего использования по имени. Это удобно для переиспользования схем в разных частях приложения. ```js import {DataProjector} from '@e22m4u/js-data-projection'; const projector = new DataProjector(); // регистрация схемы projector.defineSchema({ name: 'user', // <= имя схемы schema: { id: true, username: true, email: false, }, }); const data = { id: 10, username: 'admin', email: 'admin@example.com', }; // проекция данных по зарегистрированному имени const result = projector.project('user', data); console.log(result); // { // id: 10, // username: 'admin' // } ``` Зарегистрированные схемы могут ссылаться друг на друга, что позволяет компоновать сложные схемы из более простых. В примере ниже схема `user` использует схему `address` как вложенную. ```js import {DataProjector} from '@e22m4u/js-data-projection'; const projector = new DataProjector(); // регистрация схемы "address" projector.defineSchema({ name: 'address', schema: { city: true, zip: false, }, }); // регистрация схемы "user" projector.defineSchema({ name: 'user', schema: { name: true, address: { select: true, // видимость поля address schema: 'address', // <= имя вложенной схемы }, }, }); const data = { name: 'Fedor', address: { city: 'Moscow', zip: 123456, }, }; const result = projector.project('user', data); console.log(result); // { // name: 'Fedor', // address: { // city: 'Moscow' // } // } ``` Для ручного разрешения имен используется опция `resolver` функции `projectData`. В опцию передается функция, которая принимает имя схемы и должна вернуть соответствующий ей объект схемы. ```js import {projectData} from '@e22m4u/js-data-projection'; // функция для разрешения имен const resolver = key => { if (key === 'user') { return {id: true, name: true, password: false}; } throw new Error(`Schema "${key}" is not found!`); }; const data = { id: 1, name: 'Fedor', password: 'pass123', }; const result = projectData( 'user', // <= вместо схемы передается имя data, {resolver}, // <= разрешающая функция ); console.log(result); // { // id: 1, // name: 'Fedor' // } ``` ## Функция `projectData` Функция создает проекцию данных на основе переданного объекта схемы. Принимает исходные данные и дополнительные настройки для управления режимом строгости и областью видимости. **Сигнатура вызова:** ```js projectData(schemaOrFactory, data, [options]) ``` **schemaOrFactory** *Тип: `object` | `Function` | `string`* Определяет правила проекции. Принимает: - `object`: объект схемы проекции; - `Function`: фабрика, возвращающая схему (или имя схемы); - `string`: имя для поиска схемы через функцию `resolver`; **data** *Тип: `object` | `object[]` | `any`* Исходные данные для проекции. **options** (необязательно) *Тип: `object`* Объект с дополнительными настройками: - `strict?: boolean`: включает строгий режим; - `scope?: string`: имя активной области проекции; - `resolver?: Function`: функция для получения схемы по имени; **Возвращаемое значение:** Функция возвращает новую структуру, соответствующую исходным данным. Если передан объект, результатом будет его копия, содержащая свойства, разрешенные правилами схемы с учетом вложенности, строгого режима и активной области проекции. Для массивов возвращается новый список, к каждому элементу которого рекурсивно применена схема проекции. Примитивные значения возвращаются без изменений. ## Класс `DataProjector` Для централизованного управления схемами и удобной работы в рамках сервис-ориентированной архитектуры модуль предоставляет класс `DataProjector`. Он позволяет регистрировать именованные схемы в реестре и применять их по имени без необходимости вручную передавать функцию `resolver` при каждом вызове. Создание экземпляра: ```js import {DataProjector} from '@e22m4u/js-data-projection'; const projector = new DataProjector(); ``` ### Метод `defineSchema` Регистрирует новую схему в реестре проектора. Метод принимает объект определения, содержащий уникальное имя схемы и правила проекции. Возвращает текущий экземпляр `DataProjector`, что позволяет использовать цепочки вызовов. **Сигнатура вызова:** ```js defineSchema(schemaDef) ``` **schemaDef** *Тип: `{name: string, schema: object}`* Объект определения схемы, связывающий название схемы с правилами проекции. - `name: string`: название новой схемы; - `schema: object`: объект схемы проекции; **Возвращаемое значение:** Текущий экземпляр `DataProjector`. ### Метод `project` Выполняет проекцию данных, используя возможности внутреннего реестра схем. Метод работает аналогично функции `projectData`, но автоматически предоставляет функционал разрешения имен, связанный с добавленными ранее схемами. Метод позволяет передавать в качестве первого аргумента строковое имя зарегистрированной схемы без необходимости указывать функцию `resolver` в настройках проекции. **Сигнатура вызова:** ```js project(schemaOrFactory, data, [options]) ``` **schemaOrFactory** *Тип: `object` | `Function` | `string`* Определяет правила проекции. Принимает: - `object`: объект схемы проекции; - `Function`: фабрика, возвращающая схему (или имя схемы); - `string`: зарегистрированное имя схемы; **data** *Тип: `object` | `object[]` | `any`* Исходные данные для проекции. **options** (необязательно) *Тип: `object`* Объект с дополнительными настройками: - `strict?: boolean`: включает строгий режим; - `scope?: string`: имя активной области проекции; **Возвращаемое значение:** Метод возвращает проекцию исходных данных в соответствии с переданной схемой и настройками. ## Тесты ```bash npm run test ``` ## Лицензия MIT