@ovotech/ts-compose
An ts compiler api wrapper
Last updated 2 months ago by ikerin .
Apache-2.0 · Repository · Bugs · Original npm · Tarball · package.json
$ cnpm install @ovotech/ts-compose 
SYNC missed versions from official npm registry.

TS Compose

A DSL on top of typescript AST to make it a bit more concise.

Usage

examples/simple.ts

import { Type, printNode } from '../src';

const myInterface = Type.Interface({
  name: 'MyInterface',
  props: [
    Type.Prop({
      name: 'id',
      type: Type.Number,
    }),
    Type.Prop({
      name: 'name',
      isOptional: true,
      type: Type.Union([Type.String, Type.Null]),
    }),
  ],
});

console.log(printNode(myInterface));

// Would output:
// ==========================================

interface MyInterface {
  id: number;
  name?: string | null;
}

Example parser

Then you can load the types like this:

examples/document.ts

import { Type, document, mapWithContext, Document, DocumentContext } from '@ovotech/ts-compose';
import { printDocument, withIdentifier } from '../src';

/**
 * Lets define a fictional nested type system
 * We can have entities with strings and numbers as fields, as well as arrays and referencas.
 * We can also define a field to be an entity inline.
 */
type Field =
  | { type: 'str' }
  | { type: 'num' }
  | { type: 'ref'; name: string }
  | { type: 'arr'; items: Field }
  | { type: 'ent'; name: string; fields: { [name: string]: Field } };

interface Entity {
  name: string;
  fields: {
    [name: string]: Field;
  };
}

/**
 * Here's how an entity like that could look like
 */
const data: Entity = {
  name: 'User',
  fields: {
    id: { type: 'num' },
    name: { type: 'str' },
    posts: {
      type: 'arr',
      items: {
        type: 'ent',
        name: 'Post',
        fields: {
          id: { type: 'num' },
          title: { type: 'str' },
          content: { type: 'str' },
          user: { type: 'ref', name: 'User' },
          tags: {
            type: 'arr',
            items: {
              type: 'ent',
              name: 'Tag',
              fields: {
                size: { type: 'num' },
                name: { type: 'str' },
              },
            },
          },
        },
      },
    },
  },
};

/**
 * Now lets define the parser.
 * We want to keep track of all the entities we've parsed, since they can be defined inline.
 * That's why we have a "context" object. Its job is to keep tabs of all the references.
 *
 * A "Document" here is a combination of a typescript node and its context. { type: ..., context: ... }
 */

/**
 * Format a single field
 * @param context
 * @param field
 */
export const toFieldDocument = (context: DocumentContext, field: Field): Document => {
  switch (field.type) {
    case 'num':
      return document(context, Type.Number);
    case 'str':
      return document(context, Type.Number);
    case 'ref':
      return document(context, Type.Referance(field.name));
    case 'arr':
      const arrayType = toFieldDocument(context, field.items);
      return document(arrayType.context, Type.Array(arrayType.type));
    case 'ent':
      // eslint-disable-next-line @typescript-eslint/no-use-before-define
      return toEntityDocument(context, field);
  }
};

/**
 * Format a whole entity with all of its fields
 * @param context
 * @param entity
 */
export const toEntityDocument = (context: DocumentContext, entity: Entity): Document => {
  /**
   * Allows you to keep the context of each iteration in an
   * without modifying the original context.
   */
  const props = mapWithContext(
    context,
    Object.entries(entity.fields),
    (fieldContext, [name, field]) => {
      const fieldDoc = toFieldDocument(fieldContext, field);
      return document(fieldDoc.context, Type.Prop({ name, type: fieldDoc.type }));
    },
  );

  const entityInterface = Type.Interface({ name: entity.name, props: props.items });
  const contextWithEntity = withIdentifier(props.context, entityInterface);
  return document(contextWithEntity, Type.Referance(entity.name));
};

/**
 * Define an initial "Root" alias
 */
const rootEntity = toEntityDocument({}, data);
const rootDocument = document(
  rootEntity.context,
  Type.Alias({ name: 'Root', type: rootEntity.type }),
);

console.log(printDocument(rootDocument));

// Would output:
// ==========================================

type Root = User;

interface Tag {
  size: number;
  name: number;
}

interface Post {
  id: number;
  title: number;
  content: number;
  user: User;
  tags: Tag[];
}

interface User {
  id: number;
  name: number;
  posts: Post[];
}

Running the tests

You can run the tests with:

yarn test

Coding style (linting, etc) tests

Style is maintained with prettier and eslint

yarn lint

Deployment

Deployment is preferment by lerna automatically on merge / push to master, but you'll need to bump the package version numbers yourself. Only updated packages with newer versions will be pushed to the npm registry.

Contributing

Have a bug? File an issue with a simple example that reproduces this so we can take a look & confirm.

Want to make a change? Submit a PR, explain why it's useful, and make sure you've updated the docs (this file) and the tests (see test folder).

License

This project is licensed under Apache 2 - see the LICENSE file for details

Current Tags

  • 0.15.0                                ...           latest (2 months ago)

20 Versions

  • 0.15.0                                ...           2 months ago
  • 0.14.0                                ...           3 months ago
  • 0.13.0                                ...           4 months ago
  • 0.12.0                                ...           5 months ago
  • 0.11.1                                ...           7 months ago
  • 0.11.0                                ...           8 months ago
  • 0.10.0                                ...           8 months ago
  • 0.9.0                                ...           8 months ago
  • 0.8.2                                ...           8 months ago
  • 0.8.1                                ...           8 months ago
  • 0.8.0                                ...           8 months ago
  • 0.7.0                                ...           8 months ago
  • 0.6.0                                ...           8 months ago
  • 0.5.1                                ...           8 months ago
  • 0.5.0                                ...           8 months ago
  • 0.4.0                                ...           8 months ago
  • 0.3.2                                ...           8 months ago
  • 0.3.1                                ...           9 months ago
  • 0.3.0                                ...           a year ago
  • 0.2.0                                ...           a year ago
Downloads
Today 0
This Week 0
This Month 0
Last Day 0
Last Week 0
Last Month 1
Dependencies (1)
Dev Dependencies (8)

Copyright 2014 - 2016 © taobao.org |