Giter Club home page Giter Club logo

metaschema's Introduction

Metaschema

Metadata schema and interface (contract) definition language

ci snyk npm version npm downloads/month npm downloads license

Installation

$ npm install metaschema

Examples

const { Schema } = require('metaschema');

const schema = Schema.from({
  name: {
    first: 'string',
    last: 'string',
    third: '?string',
  },
  age: 'number',
  levelOne: {
    levelTwo: {
      levelThree: { type: 'enum', enum: [1, 2, 3] },
    },
  },
  collection: { array: { array: 'number' } },
});

const data = {
  name: {
    first: 'a',
    last: 'b',
  },
  age: 5,
  levelOne: { levelTwo: { levelThree: 1 } },
  collection: [
    [1, 2, 3],
    [3, 5, 6],
  ],
};

console.log(schema.check(data));

// Output:
// ValidationResult { errors: [], valid: true }

License & Contributors

Copyright (c) 2017-2024 Metarhia contributors. Metaschema is MIT licensed.
Metaschema is a part of Metarhia technology stack.

metaschema's People

Contributors

aqrln avatar belochub avatar dependabot[bot] avatar dmitryt avatar georgolden avatar ivan-tymoshenko avatar juliagerasymenko avatar kamre avatar lundibundi avatar mapogolions avatar nechaido avatar o-rumiantsev avatar paul0lden avatar roterentev avatar semenchenkovitaliy avatar shatanov avatar tr3nbolon3 avatar tshemsedinov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

metaschema's Issues

Missing domains

In master branch of globalstorage metaschema.domains is missing many domains after loading 'schemas/system', the only ones present are:

Map {
  'IdStatus' => Enum { values: [ 'Prealloc', 'Init', 'Actual', 'Historical' ] },
  'StorageKind' => Enum { values: [ 'Master', 'Cache', 'Backup', 'Replica' ] },
  'CategoryRealm' => Enum { values: [ 'Global', 'System', 'Local' ] },
  'CategoryFamily' => Enum {
    values:
     [ 'Registry',
       'Dictionary',
       'Table',
       'Log',
       'View',
       'History',
       'Memory' ] },
  'UserAccess' => Enum {
    values: [ 'Read', 'Insert', 'Update', 'Delete', 'Execute', 'Audit' ] },
  'AccessFlags' => Flags {
    values: [ 'Read', 'Insert', 'Update', 'Delete', 'Execute', 'Audit' ],
    enum: 'UserAccess' },
  'Compression' => Enum { values: [ 'None', 'GZIP', 'ZIP' ] },
  'SessionToken' => { type: 'string', length: 64 },
  'MediaType' => Enum {
    values:
     [ 'text/plain',
       'text/csv',
       'image/png',
       'image/gif',
       'image/jpeg',
       'image/svg+xml',
       'image/tiff',
       'application/pdf',
       'application/rtf',
       'application/zip',
       'application/json' ] },
  'SystemType' => Enum { values: [ 'Global', 'Autonomous', 'Standalone' ] },
  'ServerType' => Enum { values: [ 'Root', 'Server', 'Backup', 'Reserve' ] },
  'NodeType' => Enum { values: [ 'Master', 'Worker', 'Task' ] },
  'NodeStatus' => Enum { values: [ 'Init', 'Active', 'Pause', 'Restart', 'Hang' ] } }

Code to reproduce:

'use strict';
const metaschema = require('metaschema');
metaschema.load('schemas/system', (error, schema) => {
  if (error) {
    console.error(error);
    return;
  }

  console.log(metaschema.domains);
});

Extract introspect from generateMd

metaschema.introspect(namespace, iface): hash of Signature;
metaschema.generateMd(namespace, iface): string;
metaschema.generateMd(sig: Signature): string;

Update date/time related domains to allow Date objects usage

At the moment, some of the date-time related domains are described as numbers, for example:

Time: { type: 'number', format: 'hh:mm:ss' },
DateDay: { type: 'number', format: 'yyyy-mm-dd' },
DateTime: { type: 'number', format: 'yyyy-mm-dd hh:mm:ss' },

Such domain schemas will lead to problems when validating the values provided to functions expecting date-time values since providing Date objects will not be allowed.

I propose to set the type field for these domains to 'object', and to add another field to the domain definition (that can be called instanceof, for example), that will require the values for such domains to be the Data objects.

Validate Enum decorator

  • Enum should be treated as required: true
  • Validate fields value to be Enum.values.includes(value)
  • taxonomy/Domains.schema should be validated including Enum

Schema second pass

  • First pass: load, parse, put to collection
  • Second pass: cross-link schemas

Category schemas have a different set of fields when loaded from schema files

Category schemas have a different set of fields when loaded from schema files using metaschema.load() as opposed to using metaschema.build() method.

When using metaschema.build() method, the resulting category schema has three fields: name, definition, factory. It is being created in factorify function:

categories.set(name, { name, definition, factory });

When using metaschema.load() to load the schema definitions from files, it produces schema objects which are similar to the ones we get in the definition field when using metaschema.build():

schema, // object, schema definition

categories.set(name, schema);

It leads to problems when using the schema definitions produced by metaschema.load() with other methods (such as metaschema.validate()) since the category schema object is expected to have these fields:

metaschema/lib/schema.js

Lines 224 to 230 in aac7ad1

const record = categories.get(category);
if (!record) {
result.valid = false;
result.errors.push(`Category ${category} not found`);
return;
}
const { definition } = record;

/cc @tshemsedinov

Schema support for non floating numbers

Currently, we don't provide a way to define whether a number is an integer or not, also I would be also nice to define desired precision for the number.

I propose to add 2 Domain attributes: precision and floating.

Can not create instance of domains which are value decorators

Function createInstance in lib/schema.js can not create instances of domains which are value decorators, because we can not specify type field for them.

metaschema/lib/schema.js

Lines 137 to 141 in aac7ad1

const domain = domains.get(name);
const type = typeof value;
const expected = domain ? domain.type : name;
if (type === expected) return value;
return null;

Here an identifier type is an own JS type of value, but expected is name(name of the category, we creating instance of), because value decorators Enum and Flags can not have property type. So type === expected is false and it returns null

Validation plugin for IDE

We need plugin for IDE to validate declarative structure (JSON, JSON5, JSTP) or JavaScript and have autocomplete for fields and values defined in schemas. For the first time it will be ok to have such plugin just for single IDE.

Bug in verification link to category

Here we are getting category information from categories

metaschema/lib/schema.js

Lines 167 to 171 in b5eb4e9

const category = categories.get(field.category);
if (category) {
const error = verifyLink(
schema, schemaName, category, field.category, fieldName
);

And then trying to find out type of this category

metaschema/lib/schema.js

Lines 120 to 128 in b5eb4e9

const verifyLink = (
source,
sourceName,
destination,
destinationName,
propertyName
) => {
const sourceType = getCategoryType(source);
const destinationType = getCategoryType(destination);

metaschema/lib/schema.js

Lines 108 to 111 in b5eb4e9

const getCategoryType = category => {
const type = category.constructor.name;
return type === 'Object' ? 'Local' : type;
};

But the problem is that destination argument in function verifyLink is an object from categories, which looks like { name, definition, factory }, so getCategoryType always defines its type as Local, even if it is not.

Category factory does not process 'Logical' domain correctly

metaschema.build(schema) returns a factory, using which we are creating instances of category. So if there is a schema with Logical domain field and we trying to create an instance, where this field is set to false factory will recognize it as invalid value for this field.

metaschema/lib/schema.js

Lines 190 to 192 in aac7ad1

value = createInstance(type, value);
if (value) obj[field] = value;
else return null;

I propose to rewrite this to

value = createInstance(type, value); 
if (value !== null) obj[field] = value; 
else return null; 

Parse function signature

name(
  // Function description
  // Comments
  parameter // type (optional), meaning
  // Returns: type, meaning
  // Example: code
)

Bug in reference validation

Please test validation on globalstorage. For example Action.Category references Category, but it is not Local, it is System. One System category can reference another System category. And we need readable output too.

Illegal reference to a 'Local' category 'Category' from Action.Category,Illegal reference to a 'Local' category 'Category' from Category.Master,Illegal reference to a 'Local' category 'Catalog' from Catalog.Parent,Illegal reference to a 'Local' category 'Category' from Identifier.Category,Illegal reference to a 'Local' category 'Language' from Localization.Language,Illegal reference to a 'Local' category 'Session' from Locking.Session,Illegal reference to a 'Local' category 'SystemUser' from Locking.SystemUser,Illegal reference to a 'Local' category 'SystemUser' from Log.SystemUser,Illegal reference to a 'Local' category 'Identifier' from Log.Identifier,Illegal reference to a 'Local' category 'Role' from Permission.Role,Illegal reference to a 'Local' category 'Category' from Permission.Category,Illegal reference to a 'Local' category 'Identifier' from Permission.Bound,Illegal reference to a 'Local' category 'Action' from Permission.Actions,Illegal reference to a 'Local' category 'System' from Replication.Source,Illegal reference to a 'Local' category 'System' from Replication.Destination,Illegal reference to a 'Local' category 'Category' from Replication.Category,Illegal reference to a 'Local' category 'Category' from Schema.Category,Illegal reference to a 'Local' category 'Subdivision' from Subdivision.Parent,Illegal reference to a 'Local' category 'Role' from SystemUser.Roles

History/version decorator

  • We need to defile categories which support history
  • Only decorated categories can be included: Include(CategoryName)

Local decorator

This category decorator will limit entity relations to local server. Remote servers and entities stored there can't access and refer to this entities. Example: Session

Implement Include(def)

Use Include({ category: 'categoryName' }) in schemas to include field set from one ca category to another

Implement function contract ckecker

const buyTickets = (
  event, // number, event id
  count, // number, ticket count
  address // string, delivery address
  // Returns: boolean, success status
) => {
  metaschema.guard({ event, count, address });
};

Prepare type system and examples

Multiple layers:

  • Primitives: string, number, boolean, null, undefined, symbol, object, function, array
  • Types: ip, int, float, bool, str, char, enum, date, time, timestamp, text, function
  • Domains: Ip, Bool, Money, Passport, Nomen, Text, JSON, URL, Host, HTML, Year, Month, Day, Time, Date, DateTime, Interval, Length, Weight, Distance, Temperature, Energy, Area, Volume, Speed
  • Structures: object, record, set, map, array
  • Categories: Person, Organization, City, Country, Project, Vehicle, Asset, Building, Document, Address
    • With fields, for example: Person.Surname:Nomen, Person.Salary:Money, Person.Job:Organization

Walk API methods

Before .md generation we need introspection and inventory data structures.

Combine data definition and function signature

Prepare more cases, problems in this approach and prepare specification.

Examples:

Function signature:

doSomething(
  par1: 'string',
  par2: ['string', 10],
  par3: ['number', [0, 99999], 'nullable']
)

Data definition

{
  par1: 'string',
  par2: ['string', 10],
  par3: ['number', [0, 99999], 'nullable']
}

Implement alternative validation without reinstantiation

Now we have createInstance(category, instance / ...parts) where we pass instance (not validated data structure) or parts (values of fields according to Category schema). It is slow and obviously heavy. We need { valid: bool, errors: Array } = validate(category, instance) for lightweight validation.

Define data definition language (schema)

// Record schema
{
  continent: 'String',
  country: ['String', 10],
  city: ['String', { default: 'Kiev' }],
  zip: ['Number', [0, 99999]],
  street: ['String', [5, 30]],
  building: ['String', [1, 5], 'optional'],
  room: ['Number', 'optional']
}

// Field definition
fieldName: {
  default: 'value',
  min: 'value',
  max: 'value',
  caption: '',
  comment: '',
  type: '',
  size: '',
  signed: '',
  optional: true/false,
  hidden: true/false,
  readOnly: true/false,
  example: 'value',
  primary: true/false,
  control: 'ControlName',
  dynamic: true/false,
  transform: 'value',
  lookup: 'dataSource',
  link: 'dataSource',
  master: 'dataSource',
  index: 'value'
}

discuss: Rename Bitmask -> Flags

This way it's not limiting an internal representation to actually using bitmasks to represent the data.
Also, if anyone has other suggestions for another name feel free to speak out, as I don't think Flags is good enough.
Other names may be

  • BitFlags - I think just Flags is better and Bit prefix doesn't bring any value into it
  • Set - good, but too broad, it may not be intuitive that you can actually use it as Flags.

/cc @tshemsedinov @nechaido @belochub

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.