@hn3000/metamodel
TypeScript icon, indicating that this package has built-in type declarations

1.9.12 • Public • Published

Meta Model for JavaScript Apps

Coming from statically typed languages like Pascal, C and C++, I always wanted to have more strict typings for my JavaScript classes. While TypeScript allows me to describe the data using interfaces, I feel it lacks RTTI -- runtime information about the objects involved that would allow me to construct user interfaces dynamically and validate incoming data (either from some remote connection or typed in by a user) against the type information.

This is my attempt at building something to fill this gap.

A metamodel is created like this:

const sampleObject = {
    lala: 12,
    blah: "Some String",
    blub: 3.1415 * 12
};

const modelTypes = require("metamodel").modelTypes;

const model = modelTypes.addObjectType('sample')
  .addItem('lala', modelTypes.type('number/int'))
  .addItem('blah', modelTypes.type('string'))
  .addItem('blub', modelTypes.type('number'));

Once the model exists it in the modelTypes registry, it can always be referred to by name:

const model = modelTypes.type('sample');

And input data can be validated by the model:

const inputData = {
    lala: "12",
    blah: "Another String",
    blub: 27.12
};

const context = modelTypes.createParseContext(inputData, model);
context.allowConversion = true;
const isValid = context.validate();
if (context.warnings.length) {
    console.warn(`context.messages.map(e => e.msg).join(', ')`);
}
if (context.errors.length) {
    console.error(`context.errors.map(e => e.msg).join(', ')`);
    throw new Error('Validation failed');
}

// turn text input into actual objects
const parsedInput = context.parse();

At this point, context will contain warnings and errors if the data does not fit the metamodel. With allowConversion=true, the metamodel will parse "12" into a number, if allowConversion=false, the string value will result in an error message.

Using JSON Schema

Parsing a JSON schema into a metamodel uses a special kind of IModelTypeRegistry, which can not only parse the schemas, but also acts as a registry for the parsed schemas:

  
  const schemaResponse = await fetch(schemaUrl);
  const schema = await schemaResponse.json();

  const models = new ModelSchemaParser();

  const model = models.parseSchemaObject(schema) as IModelTypeComposite<any>;

  // just a different way to get at the model for this schema:
  const modelByName = models.type(schema.id); 

And that model can then be used the same as shown above.

You can also provide some defaults for the parser to amend imported schemas with some useful defaults, like e.g. a regex for all strings:

  const models = new ModelSchemaParser(undefined, {
    strings: { pattern: /^[^\u0000-\u001f\u007f-\u009f\"<>\{\}\[\]]*$/ },
  });

  const model = models.parseSchemaObject(schema) as IModelTypeComposite<any>;

Readme

Keywords

Package Sidebar

Install

npm i @hn3000/metamodel

Weekly Downloads

6

Version

1.9.12

License

MIT

Unpacked Size

795 kB

Total Files

123

Last publish

Collaborators

  • hn3000