1.0.5 • Published 5 months ago

script-type-js v1.0.5

Weekly downloads
-
License
ISC
Repository
github
Last release
5 months ago

Script Type JS

Dynamic JS typed code, using an inheritance prototype and replacing class properties and methods with a validation arguments function. Generates errors with wrong type information and crashes front-end UI

Installation

Install Script Type JS with npm

  npm i script-type-js

Activation

Configuration file

// script_type.config.js
import ScriptTypeJS from "script-type-js";

// mode = 'dev' activate type checking and the errorMode behaviour, other value deactivate
// errorMode = 'frontend' destroy DOM and show error messages on the console and the document.body, other value for only console display
ScriptTypeJS.mode = 'dev';
ScriptTypeJS.errorMode = 'frontend';

export default ScriptTypeJS.apply();

Main file of our project

Just import our configuration file :

import ScriptTypeJS from "./script_type.config";

Usage/Examples

Enums

import { Enum } from "script-type-js";

const Sex = new Enum({
    male: 1,
    female: 2
});

Personalized types

// Object Type
const TPerson = T({ firstname: String, lastname: String, age: Number });

// Multi native types
const TAvailableType = T({String, Number});

Class

import ScriptTypeJS, { Enum } from "script-type-js";

Sex = new Enum({
    male: 1,
    female: 2
});

 class Person {    
    set sex(value = Sex) { this._sex = value; }
    get sex() { return this._sex; }

    get fullname() { return this._fullname; }
    set fullname(value) { this._fullname = value; }

    constructor() {
        this._fullname = '';
        this.firstname = '';
        this.language = Language;
        this.lastname = T({ String, Number });
    }

    // Function setFullName accept multitype for argument lastname
    setFullName(firstname = String, lastname = { String, Number }) {
        this.firstname = firstname;
        this.lastname = lastname;
        this._fullname = firstname + ' ' + lastname;
    }

    setSexe(sex = Sex) {
        this.sex = sex;
    }

    chooseLanguage(language = Language) {
        this.language = language       
    }

    apply(p = Person) {
        this.fullname = p.fullname;
        this.firstname = p.firstname;
        this.lastname = p.lastname;
    }

    static create(fullname = String('John Doe')) {
        const p = new Person();
        p.fullname = fullname;
        const names = fullname.split(' ');
        p.firstname = names[0];
        p.lastname = names[1];
        return p;
    }
}

// Declare to Script Type
ScriptTypeJS.declare({ Sex, Person });

Class with interface in function argument

class SayHello {
    static staticProp = Number(10);
    static staticFunc() { console.log('Hello'); }

    classProp = String('Hello');

    // Method need a Speaker implementation object
    static run(speaker = Speaker, person = Person) {
        const now = new Date();

        speaker.say('Hello', person, new Date());
    }
}

ScriptTypeJS.declare({ SayHello });

Interface

Class with multi-interfaces implementation

  • Interface file Translator.js
import ScriptTypeJS, { Enum } from "script-type-js";

const Language = new Enum({
    'FR': 'French',
    'EU': 'English',
    'DE': 'Deutch',
});

class Translator {
    translate(text = String) { }

    setLanguage(language = Language) { }
}
  • Interface file Speaker.js
class Speaker {
    static helloWorld() { }

    say(text = String, to = Person, at = new Date()) { }
}
  • Class file EnglishSpeaker.js
// Class with interfaces implementation
class EnglishSpeaker {    
    say(text, to, at = Date()) {
        console.log(`On ${at.toLocaleString()}\nTo ${to.fullname}: ${text}`);
    }

    translate(text) {
        console.log(`Ok, i'm going to translate "${text}" in english`);
    }

    setLanguage(language) {
        console.log(`I translate ${language}`);
    }
}

// Declare in ScriptTypeJS
// Interfaces are automatically declared with their implementations and could be uses as a type
ScriptTypeJS.declare(EnglishSpeaker).implements(Speaker, Translator);

In Action

Interface contract checking

  • Good script
class EnglishSpeaker {    
    say(text, to, at = Date()) {
        console.log(`On ${at.toLocaleString()}\nTo ${to.fullname}: ${text}`);
    }

    translate(text) {
        console.log(`Ok, i'm going to translate "${text}" in english`);
    }

    setLanguage(language) {
        console.log(`I translate ${language}`);
    }
}

ScriptTypeJS.declare(EnglishSpeaker).implements(Speaker, Translator);
  • Bad change

    Missing method translate

class EnglishSpeaker {    
    say(text, to, at = Date()) {
        console.log(`On ${at.toLocaleString()}\nTo ${to.fullname}: ${text}`);
    }

    setLanguage(language) {
        console.log(`I translate ${language}`);
    }
}

ScriptTypeJS.declare(EnglishSpeaker).implements(Speaker, Translator);

Throw error:

Methods translate are not defined on class EnglishSpeaker (class EnglishSpeaker implement interface Translator)

Bad argument naming

class EnglishSpeaker {    
    say(text, person, at = Date()) { // bad naming of agrument #2
        console.log(`On ${at.toLocaleString()}\nTo ${to.fullname}: ${text}`);
    }

   translate(text) {
        console.log(`Ok, i'm going to translate "${text}" in english`);
    }
    setLanguage(language) {
        console.log(`I translate ${language}`);
    }
}

ScriptTypeJS.declare(EnglishSpeaker ).implements(Speaker, Translator);

Throw error:

Argument #name are wrong in function say (text,person,at = Date()) declaration: to expected for name of argument, person is given

Value assignment checking

  • Good script
import ScriptTypeJS, { Enum } from "script-type-js";

import Person, { Sex } from "./Person";
import { EnglishSpeaker } from "./Test";
import { SayHello } from "./SayHello";
import { Language } from "./Translator";

const englishSpeaker = new EnglishSpeaker();

const john = new Person();
john.setFullName('John', 'DOE'); 
john.setFullName('John', 1);      // Accepted with the multi type { String, Number }
john.sex = Sex.male;

englishSpeaker.say('Hello my friend', john);
  • Bad changes
john.sex = 3;

Throw error:

Method set: Argument value (#1) must be Enum { male: 1, female: 2 }, Number 3 is given

john.setFullName('John', true);

Throw error:

Method setFullName: Argument lastname (#2) must be Type { String: String, Number: Number }, Boolean true is given

englishSpeaker.say('Hello my friend', 'john');

Throw error:

Method run: Argument person (#2) must be a Person, String is given

BABEL

If you use babel you must exclude the transform-parameter plugin.

"presets": [
        [
            "@babel/preset-env",
            {                
                "exclude": ["transform-parameters"]
            }
        ],
    ]

Limitation

Instance type checking is automatically applied when a first method or setter/getter call is made. In the case of a direct assignment of a property without any method call, getter or setter beforehand, the check is not performed. To fix this, you can use the static Class.instanciate(this) method at the end of the constructor or the static factory method

1.0.5

5 months ago

1.0.4

5 months ago

1.0.3

5 months ago

1.0.1

5 months ago

1.0.0

5 months ago