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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@itgenio/edik-reflection

v0.0.31

Published

Рефлексия

Downloads

141

Readme

Reflection

  • зависимость nanoid для генерации ref id

Общее

Type.$$gemeta

Все данные об объекте хранятся в его типе в поле $$gemeta. Удобно хранить связанные с типом мета-данные в его прототипе.

Дальнейшим развитием может быть сохранение не по строчному ключу, а символьному (Symbol, так делает Mobx)

Какие мета-данные есть у типа?

  • name:string используется для поиска типа в качестве уникального идентификатора.

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

  • displayName?:string для красивости
  • isComponent?:boolean компонент или нет (доп. атрибут для инспектора)
  • fields?:{ name:string }[] поля
  • inline?:boolean нужно ли инлайнить,т.е. вставлять объекты такого типа по месту не вынося в map.

Для типа SerializedRootObject есть поддержка версионирования. (текущая версия схемы будет лежать в поле __meta.v)

Про обычные и inline-типы

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

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

Если объект есть в списке - значит мы уже обработали такой объект и можно идти дальше.

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

Важно: при копировании полей объекта такие ссылки на объекты не будут копироваться.

Пример:

class SomeComponent extends CBaseComponent {
  field: CBaseComponent;// предположим наш компонент ссылается на какой-то компонент.
}

const comp:SomeComponent = /*...*/;

const copy = comp.clone(); //копируем

assert(comp.field === copy.field);//!!! хотя сам компонент скопировался, ссылка при этом указывает на старый объект!

Такие объекты имеют Обычный тип.

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

Для этого нужны inline-типы.

Самый простой пример - тип Color. Мы не хотим чтобы на него ссылались разные объекты, при этом при копировании создается новый экземпляр данного типа.

Пример:

class SomeComponent extends CBaseComponent {
  color: Color; //Color - inline-тип
}

const some:SomeComponent = ...;
const copy = some.copy(); //копируем

assert(some.color !== copy.color);//ссылки разные, т.к. цвет скопировался!

TODO

  • сократить размер?
    • если в массиве(+ set и map) все элементы - ссылки, то можно применить специальный флаг.(т.к. в большинстве случаев массивы однотипны)

Процесс регистрации

  • берем тип
  • регистрируем его поля в мету
  • далее идет по иерархии ниже и регистрируем следующий тип, если нужно.
  • так же регистрируем в общей хранилище Object.$$gemetamap : Map<string, Type> чтобы в дальнейшем из любого места могли получить тип по имени.

Если на верхнем уровне есть поле с именем, как и на нижних уровнях, то будет браться поле из верхнего уровня.

class CBase {
  id: string; //для CBase регаем id=>string
}

class CSome extends CBase {
  id: number; //для CSome регаем id=>number;
}

//getField(CSome,'id') => number;
//getField(CBase,'id') => string;

Early(ранняя) регистрация

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

В таком случае наступает ранняя регистрация для базового типа. Это значит:

  • мы не знаем точно про доп. атрибуты и имя
  • мы знаем только о полях

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

Сериализация

Поддержка и фичи

Типы:

  • type Primitives = string | number | boolean
  • Array<any>
  • Set<any>
  • Map<string, any>

Есть таблица

type ObjId = string;
type ObjData = any;

const objects = new Map<ObjId, ObjData>();

Все объекты(за исключением inline-типов) сериализуются в таблицу. Ссылки на такие объекты сериализуются как строки-указатели на ID объекта из таблицы.

Сериализация

У Serialized*** есть поле __meta.map хранящее все объекты, на которые могут ссылаться внутренние объекты.

Десериализация

Для объектов:

  • ID
  • тип
  • остальные данные

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

Десериализация происходит в два этапа.

Первый этап

На первом этапе создаются экземпляры объектов. При этом берется тип из сериализованного объекта.

Второй этап

На втором этапе объекты связываются друг с другом

Объекты

Запоминаем ID и помечаем поле как ссылка на объект

Массивы

Запоминаем ID и помечаем, какие индексы как ссылки

Что не работает (так задумано)

Ссылки на общий raw object, raw array

import { Serializer } from './serializer';

const s1 = new Type();
const s2 = new Type();

const sharedRawObj = { a: '1' };

s1.raw = s2.raw = sharedRawObj; //вот так не работает!

const obj = { s1, s2 };

const dobj = Serializer.serialize(Serializer.deserialize(obj));

//после десериализации, dobj.s1.raw !== dobj.s2.raw, ссылка не сохранилась

PoC / Ideas

External links

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

@gtype({ name: 'SomeType' })
class SomeType {
  @gserializable()
  id: string = 'randomId';

  @gserializable()
  externalLink?: SomeType;
}

const exernalObj = new SomeType();

const obj = new SomeType();
obj.externalLink = exernalObj;

Как сейчас:

const dobj = Serializer.deserialize(Serializer.serialize(obj));

assert(dobj.externalLink !== exernalObj); // сейчас вот так!

Предложение:

//serialize

const externalLinks = [externalObj];

const serialized = Serializer.serialize(obj, { externalLinks });

// deserialize

const dobj = Serializer.deserialize(serialized, { externalLinks: allObjsAndComps });

assert(dobj.externalLink === exernalObj);

interface ILinkable {
  id: string;
}

Подробнее:

Когда встречаем объект, который находится в externalLinks, подменяем тип на новый тип ExternalLink:

class ExternalLink {
  id: string;
}