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 🙏

© 2025 – Pkg Stats / Ryan Hefner

raml-typesystem-shapes

v0.0.23

Published

**Problem statement**: different use cases require us to expose different representations(shapes) of same business entity.

Readme

RAML Typesystem Shapes

Problem statement: different use cases require us to expose different representations(shapes) of same business entity.

Diagram

One way to model it in Callable is scopes, however some times you need to model different shapes of the same model entity as a separate RAML types.

This repository contains a typescript module supporting an alternative approach to modelling different shapes of the model entity.

Background

Let's say that we have a Task data type which models a Task business entity

Task:
  properties:
    id: integer
    name: string
    description: string
    subTasks: Task[]

When new Task is being added in the system we prefer to represent incoming payload with following RAML type:

NewTaskData:
  properties:
    name: string
    description: string

Now we need to mark that NewTaskData is not conceptually different entity but just a representation of the Task data type in Callable this may be done by using shapeOf annotation:

This annotation is defined by the following annotation type:

shapeOf:
  type: common.RAMLObjectTypeRef  

It is important that both target and value of this annotation may only be pure object types(no unions)

so if we would like to mark that NewTaskData is the shape of the Task we should update NewTaskData to look as in the following example:

NewTaskData:
  properties:
    (callable.shapeOf): Task
    name: string
    description: string

Instance Transformation:

Now let's talk about how callable transforms instance of the NewTaskData into the instance of the task:

Transformation from Shape type to Domain type

We use following algorithm to perform a conversion which is performed for every property of source type.

  1. If target type has a property with a same name: check if the system knows how to transform value of this property into value of the target property. If transformation is undefined then whole conversion of model instance to target instance can not be executed

  2. Else if target property has an annotation property and this annotation values is the name of the property of domain class, or qualified name of the property of the source type, then: check if the system knows how to transform value of this property into value of the target property. If transformation is undefined then whole conversion of model instance to shape instance can not be executed

  3. If target property value has a default it is initialized into it's default value, if target is an array and if it is a required property it is initialized into empty array, if target is has an object type and it is required it is initialized into empty instance of target type (using the same scheme as for property value), otherwise it stays undefined.

  4. If target property is pattern or additional property then throw error(this usecase is not supported at this moment)

Transformation from Domain type to Shape type

We use following algorithm to perform a conversion which is performed for every property of shape type.

  1. If domain type has a property with a same name: check if the system knows how to transform value of this property into value of the target property. If transformation is undefined then whole conversion of model instance to target instance can not be executed

  2. Else if shape property has an annotation property and this annotation values is the name of the property of domain class, or qualified name of the property of the source type, then: check if the system knows how to transform value of this property into value of the target property. If transformation is undefined then whole conversion of model instance to shape instance can not be executed

  3. Else abort with error (all properties of shape type should be resolved to some properties of domain type).

Value conversion

Value conversion is executed by the following algorithm:

  1. if values have a type with same structural constraints then no conversion is needed
  2. If target value is a shape of model property value then conversion from model to shape is executed
  3. If target value is a reference to model property value then conversion to reference is executed
  4. If target value type is assignable from source value type return a model property value
  5. If the source value is a reference to model property value, then system checks if it is capable to resolve reference to the instance, and if there is no possibility to resolve it conversion should abort, otherwise resolved reference should be written to the target property.
  6. Otherwise conversion can not be performed and algorithm should abort.

Examples:

For example lets assume that we convert following instance of NewTaskData into instance of Task:

name: Buy milk
description: I should buy the milk

the result will be

name: Buy milk
description: I should buy the milk
friends: []

Now lets look on the following example:

PersonData:
  (core.shapeOf): Person
  properties:
    name: string
    lastName:
      (core.property): last_name
      type: string

In this example PersonData property name will be inited from Person property name, and PersonData property lastName will be inited from Person property last_name

More complex example:

Task:
  properties:
    id: integer
    name: string
    description: string
    subTasks: Task[]
TaskData:
    properties:
      id: integer
      name: string
      description: string
      subTasks: 
        type: array
        items:
          type: integer
          (shapes.reference): Task.id        

in this example subTasks property of the TaskData will be inited by values of the id property of the values subTasks property of the Task instance

Usage

This module exports following typescript functions:

  • transform(instance:any,source:Type,target:Type,referenceResolver?: (v:any,referenceType:Type)=>any): any - transforms an instance from one representation to another

  • transformFunc(source:Type,target:Type,referenceResolver?: (v:any,referenceType:Type)=>any): any - returns a function capable to transform instances from one representation to another or null if transformation can not be performed

  • isShapeOf(source:Type, target:Type) - checks if source type is shape of target type

  • isDomainOf(source:Type, target:Type) - checks if source type is domain of target type.

Usage example:

import shapes=require("raml-typesystem-shapes")
let tFunc=shapes.transformFunc(domainType, shapeType)//aquire a transformation function
var transformed=tFunc({name: "Pavel", lastName: "Petrochenko"});//perform transformation