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

babel-plugin-transform-metadata

v4.0.2

Published

Reflection metadata support for classes and functions with flowtype type aliases support

Downloads

245

Readme

babel-plugin-transform-metadata

Strict, optimized and smart reflection metadata generator for classes and functions from flowtype metadata.

  • Supports arrows and function expressions
  • Metadata provided for array and object-style arguments
  • Generics and type arguments support

Examples

Interface as value

Flowtype and typescript reflection does not support type annotations as value keys, so we use some trick with typecast.

In:

// @flow

import _ from 'babel-plugin-transform-metadata/_'

class A {}

export interface C {
    a: A;
}
class MyClass {
    constructor(c: C) {}
}

const id = (_: C)

Out:

'use strict';

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var A = function A() {
    _classCallCheck(this, A);
};

var MyClass = function MyClass(c) {
    _classCallCheck(this, MyClass);
};

MyClass.displayName = 'MyClass';
MyClass._r = [0, ['C']];


var id = 'C';

Mark function

In:

// @flow

function fn(a: A) {
    function fn2(a: A) {

    }
}

Out:

"use strict";

function fn(a) {
    function fn2(a) {}
}
fn.displayName = "fn";
fn._r = [1, [A]];

Components metadata

In:

// @flow
class A {}
interface State {s: A}
function ComponentD(rec: {p: number}, state: State) {
    return <div>AA</div>
}

Out:


function A() {}

function ComponentD(rec, state, createVNode) {
    return createVNode(2, 'div', null, 'AA');
}

ComponentD.displayName = 'ComponentD';
ComponentD._r1 = [{
    s: A
}];

Type parameters

In example below, ISource and IStatus to ids mappings are configured in .babelrc. Only first type parameter used.

In:

// @flow
type ResultOf<F> = _ResultOf<*, F>
type _ResultOf<V, F: (...x: any[]) => V> = V

function fn(a: A, b: Class<B>, f: ResultOf<typeof factory>, sA: ISource<A>, saf: IStatus<A | B>) {
    function fn2(a: A) {
    }
}

Out:

'use strict';

function fn(a, b, f, sA, saf) {
    function fn2(a) {}
}

fn.displayName = 'fn';
fn._r3 = 'babel-plugin-transform-metadata/src/__tests__/data/AllFeatures.js';
fn._r2 = 2;
fn._r1 = [A, B, factory, {
    _r4: 1,
    v: [A]
}, {
    _r4: 2,
    v: [A, B]
}];

For more examples see ./src/__tests__/data

Metadata

To each function plugin adds following metadata:


  /**
   * Class constructor or function argument
   */
  type IArg = IFunction | {

    /**
     * User defined interface id, see markGenerics
     */
    _r4: number;
    /**
     * Type arguments
     */
    v: IFunction[];
  }

  /**
   * Each function or class constructor
   */
  interface IFunction {
    (...args: any[]): any;
    /**
     * constructor/function arguments list
     */
    _r1?: IArg[];

    /**
     * bit flags: 1 - jsx, 2 - fn
     */
    _r2?: number;

    /**
     * relative filePath for hmr and debugging
     */
    _r3?: string;
  }

.babelrc options

Add before babel-plugin-transform-decorators-legacy and other transformation plugins.

interface IOptions {
   /**
    * if true - add metadata only to exported function/classes
    */
    onlyExports?: boolean;

    /**
     * if true - add file path to each exported class or function for hot reloading
     */
    addFileName?: boolean;

    /**
     * if true - add function/class name to each exported class or function
     */
    addDisplayName?: boolean;

    /**
     * how to generate interface name tokens:
     * fullPath - type name + crc(file with type path), typeName - type name only
     */
    typeNameStrategy?: 'typeName' | 'fullPath';

    /**
     * createElement/createVNode factory name, used for [reactive-di](https://github.com/zerkalica/reactive-di) components
     */
    jsxPragma?: string;

    /**
     * Interface to ids mappings: {'ISource': 1, 'IStatus': 2}
     */
    markGenerics?: {[id: string]: number};
}

Example .babelrc:

{
    "plugins": [
        "syntax-flow",
        "transform-decorators-legacy",
        ["transform-metadata", {
            "addFilename": true,
            "onlyExports": false,
            "markGenerics": {"ISource": 1, "IStatus": 2},
            "typeNameStrategy": "typeName",
            "jsxPragma": "createVNode"
        }]
    ]
}

Restrictions

For interface-based metadata we need to convert types to unique string tokens, something like this:

import type {T} from './types'

function test(t: T) {}
Reflection.defineMetadata(['T.types'], T)

JS module import subsystem is poor and nothing is doing in ES standarts for improving it. It's no clean way to identify imported interface in babel plugin, if import path is relative:

Types are same, but import paths is different:

import type {T} from './types'
import type {T} from '../data/types'

Ideally, set "typeNameStrategy": "fullPath" and always use absolute path for types via name_mapper in .flowconfig:

module.name_mapper='^babel-plugin-transform-metadata/i/\(.*\)' -> '<PROJECT_ROOT>/i/\1'
import type {T} from 'babel-plugin-transform-metadata/i/types'
import type {R} from './internalTypes'

function test(t: T, r: R) {}
Reflection.defineMetadata(['T.crc1', 'R.crc2'], test)
// where crc1 is crc32('babel-plugin-transform-metadata/i/types')
// where crc2 is crc32('internalTypes')

Relative paths supported, but some collisions possible, if types with equal names are defined in different files with equal names:

import type {T} from '../t2/internalTypes'
import type {T} from '../t1/internalTypes'

If "typeNameStrategy" is "fullPath", types always will be placed in separate files to avoid collisions like this:

// t1.js
export type T = {
    some: string;
}

function test(t: T) {}
Reflection.defineMetadata(['T'], test)
// t2.js
import type {T} from './t2'

function test2(t: T) {}
Reflection.defineMetadata(['T.t2'], test2)

If "typeNameStrategy" is "typeName", import paths will be ignored. But possible collisions with equal type names in different files.

Credits

babel-plugin-angular2-annotations