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

@metamatter/core

v1.1.9

Published

MetaMatter is a library for building runtime type definition generation. It is built with <a href="https://www.typescriptlang.org/" target="_blank">TypeScript</a> and combines the concepts of `Meta-Programming`, to create `type-safe`, `scalable` environme

Downloads

10

Readme

Description

MetaMatter is a library for building runtime type definition generation. It is built with TypeScript and combines the concepts of Meta-Programming, to create type-safe, scalable environment for (mainly) Frontend development.

Philosophy

There are numbers of libraries for building a Node.js server-side applications. However, there is an issue when it comes to communicate between Frontend and Backend no matter which backend language we are using. Type Definitions, would be troublesome when it comes to Agile development style. Frequent updates on APIs makes it hard to develop projects in a type-safe environment.

MetaMatter aims to address this issue, by providing a lightweight, less configuration tools.

Installation

> yarn add @metamatter/core
# or
> npm install @metamatter/core

Usage

There are three decorators at the moment.

  • @Property()
  • @Enum()
  • @Subclass()

@Property()

This is the basic decorator to tell the program to store the decorated field as part of the definition output.

Due to the limitation of Reflection in TypeScript, union types, interface, enum, Promise, Array are not working as expected, the implementation would not be as usual as it be.

Example

import { Property } from '@metamatter/core';

class User {
    @Property()
    username: string;

    @Property({ type: String })
    hobbies: string[];

    @Property({ nullable: true })
    phone?: string;
}

// Will produce the follow output:
const definition = {
    name: 'User',
    type: 'interface',
    definition: '{username: string, hobbies: string[], phone: string | null}',
};

@Enum()

This decorator will work the same way as enum does, but in JavaScript, enum will be translated to a frozen object, which cannot be able to apply any decorators, so we suggest keeping the enum in a class form with static fields.

Due to the limitation of Reflection in TypeScript, union types, interface, enum, Promise, Array are not working as expected, the implementation would not be as usual as it be.

Example

import { Enum } from '@metamatter/core';

@Enum()
class UserRole {
    static readonly ADMIN = 'ADMIN';
    static readonly USER = 'USER';
}

// Will produce the follow output:
const definition = {
    name: 'UserRole',
    type: 'enum',
    definition: '{ADMIN: "ADMIN", USER: "USER"}',
};

@Subclass()

At some point that your application might grow in size, some class might share the same name but in different structure, in that way the program might generate two different interfaces with the same name, this is not what we want. That's why we need @Subclass decorator.

Since nested class cannot apply decorators as well, we need to declare it outside the class and assign it as a static property of another class

Example (Suggested)

import { Subclass, Property } from '@metamatter/core';

@Subclass()
class Wallet {
    @Property()
    balance: number;
}

class User {
    static Wallet = Wallet;

    @Property({ type: User.Wallet })
    wallet: InstanceType<typeof User.Wallet>;
}

Example

import { Subclass, Property } from '@metamatter/core';

@Subclass()
class Wallet {
    @Property()
    balance: number;
}

class User {
    @Property()
    wallet: Wallet;
}

The above examples work the same way, but just in different style.

MetaMatter

This is the main class of the library, it provide two simple functions

  • getPropertyTree
  • generateTypeDefinition

MetaMatter.getPropertyTree

It accepts a class as parameter and it will return a complete Type tree of all of it's properties.

Example

// What a Type look like
interface Type<T> {
    type: string;
    isPrimitive: boolean;
    isArray: boolean;
    isEnum: boolean;
    isNullable: boolean;
    isSubclass: boolean;
    body: T extends object ? (object extends T ? T : { [P in keyof T]: Type<ExcludeArray<T[P]>> }) : null;
    toString: (prefix?: string) => string;
    toDefinition: (prefix?: string) => string;
}
import { MetaMatter, Property } from '@metamatter/core';

class User {
    @Property()
    name: string;

    @Property()
    age: number;
}

const tree = MetaMatter.getPropertyTree(User);

// Output
const tree = {
    name: {
        type: 'string',
        isPrimitive: true,
        isArray: false,
        isEnum: false,
        isNullable: false,
        isSubclass: false,
        body: null,
        toString: () => 'string',
        toDefinition: () => '';
    },
    age: {
        type: 'number',
        isPrimitive: true,
        isArray: false,
        isEnum: false,
        isNullable: false,
        isSubclass: false,
        body: null,
        toString: () => 'number',
        toDefinition: () => '';
    },
}

MetaMatter.generateTypeDefinition

It accepts a class as parameter and it will produce an array of Definition.

Example

// What a Definition look like
interface Definition {
    name: string;
    type: 'interface' | 'enum';
    definition: string;
}
import { MetaMatter, Property, Subclass } from '@metamatter/core';

@Subclass()
class Wallet {
    @Property()
    balance: number;
}

class User {
    @Property()
    name: string;

    @Property()
    age: number;

    @Property({ nullable: true })
    wallet?: Wallet;
}

const definitions = MetaMatter.generateTypeDefinition(User);

// Output
const definitions = [
    {
        name: 'User',
        type: 'interface',
        definition: '{name: string, age: number, wallet: User$Wallet | null}',
    },
    {
        name: 'User$Wallet',
        type: 'interface',
        definition: '{balance: number}',
    },
];