Codevendor / inferjs-library

A runtime library that allows you to infer rules for extended type checking in JavaScript.
https://inferjs.com
MIT License
1 stars 0 forks source link
es6 esmodule infer infer-object inferjs inferjs-compiler inferjs-library inferobject javascript js jsdoc node nodejs type typechecking types

InferJS Library

Heading  InferJS-Library: Overview

InferJS-Library allows you to easily add runtime type checking by utilizing JSDoc multi-line comments in both client and server side JavaScript. The library is part of a bigger project named InferJS.

InferJS is provided with an InferJS-Compiler. The compiler interprets your JSDoc comments from your source code and compiles them into an InferObject file, that you can import into any JavaScript file.

With this library, you can also enable extended type checking and narrow down your data types with @infer expectation rules. Check out the examples below, to see how InferJS can save you time and money from costly bugs through development and release.

Built With

Heading  InferJS-Library: Installation

To install the latest version of InferJS-Library locally with npm:

Install: [Locally]()

npm install inferjs-library --save

Install: [Globally]()

npm install -g inferjs-library

Optional: If you would like to download the repo source code with git:

git clone https://github.com/Codevendor/inferjs-library.git

Heading  InferJS-Library: Browser Version Instructions

If you would like to use the InferJS-Library from the browser, please select a precompiled/minified version and module type from the dist folder. There are 3 types of modules supported (esmodule,commonjs,script). The latest folder contains the latest version of the library.

Optional: Compiling the Latest Version of InferJS-Library

If you are missing the dist folder or would like to compile the latest version, follow the steps below.

Install Webpack

To build yourself, you will need to install Webpack version 5+ with the following commands. The commands need to be run from where the package.json is located. Or you can install them globally with the -g identifier.

Webpack Latest Install

// Local Install
npm install --save-dev webpack
npm install --save-dev webpack-cli

or

// Global Install
npm install -g --save-dev webpack
npm install -g --save-dev webpack-cli

The latest version of webpack 5+ automatically installs the terser-webpack-plugin with it. If it doesn't, you will need to install it as well, from where the package.json is located. The Terser plugin is used for minimizing/compressing the library code for use in the browser.

Optional - Terser Webpack Plugin

After the node modules under devDependencies are installed, you can run the build process from where the package.json is located.

npm run build

Heading  InferJS-Library: Compiling InferObject Files

In order to use the InferJS-Library, you will need to compile an InferObject with the InferJS-Compiler.

For more information on installing the InferJS-Compiler and its usage click here.

Heading  InferJS-Library: Usage

Browser - Usage Instructions

Copy one of the minimized inferjs-{version}.min.js from the dist folder to your website. Copy the pre-compiled [InferObject]() file to your website, that was created with the InferJS-Compiler.

Add both to your webpage for type checking. You only need to recompile with the InferJS-Compiler, if you change your JSDoc multi-line comments, @param, @type, @inferid or @infer tags.

Below are examples for using InferJS-Library in your code.

Browser ESModule Import Example - Client side

<script type="module">
  import { InferObject } from "./inferobject.js";
  import { InferJS } from "./esmodule/inferjs-{version}.min.js";
  const inferjs = new InferJS(InferObject);
</script>

Browser JavaScript Script Tag Sync Example - Client Side

<script src="https://github.com/Codevendor/inferjs-library/raw/main/inferobject.js"></script>
<script src="https://github.com/Codevendor/inferjs-library/raw/main/script/inferjs-{version}.min.js"></script>
<script>
const inferjs = new InferJS(InferObject);
</script>

Node.js ESModule Import - Server Side

import { InferObject } from "./inferobject.js";
import { InferJS } from "./esmodule/inferjs-{version}.min.js";
const inferjs = new InferJS(InferObject);

Node.js CommonJS Require - Server Side

const InferObject = require("./inferobject.js");
const InferJS = require("./commonjs/inferjs-{version}.min.js");
const inferjs = new InferJS(InferObject);

There are many ways to utilize the InferJS-Library. The example above, imports in the pre-compiled [InferObject]() file that was created with the InferJS-Compiler. Intialize the InferJS-Library class with the [InferObject]() file you want to use.

// Intialize through constructor
const inferjs = new InferJS(InferObject);

// or intialize through property
const inferjs = new InferJS();
inferjs.inferObject = InferObject;

Once the InferJS-Library and [InferObject]() file are included at the top of your file you can then utilize the type checking features. Below is an example of how to create a JSDoc multi-line comment for type checking.

Custom JSDoc Multiline Comment with Custom Infer Expectations

/**
 * Test case scenario for JavaScript inferjs function.
 * @category tests
 * @function foo
 * @param {string} msg - The message to send through console.log().
 * @param {(number|string)} id - The id of the message.
 * @param {boolean} [send=true] - Whether to send your message.
 * @infer {string} msg {STRING-NOT-EMPTY} - Checks if string is not empty.
 * @inferid foo
 */
function foo(msg, id, send) {

    inferjs.check('foo', arguments);
}

// Example Normal Call
foo('test', 1234, true);

Heading  InferJS-Library: Type Checking with JSDoc [@param]()

The JSDoc tag @param below specifies a method's parameter type(s), name and description.

Fomart for [@param]():

Single type check example:
/**
 * @param {string} msg - The message to send through console.log().
 */
Multi type check example:
/**
 * @param {(null|string)} msg - The message to send through console.log().
 */

InferJS-Library reads the precompiled [InferObject]() file and uses it to process all type checking and inferred expectations.

Below is a list of standard and extended types that can be checked:

Standard JS Types               Description
[undefined]() An undefined type: undefined
[null]() A null type: null
[boolean]() A boolean type: true or false
[number]() A number type: 1000 or 10.25
[bigint]() A big integer type: 1010101112233343545545545446n
[string]() A string type: foo1 or foo2
[symbol]() A symbol type: Symbol
[function]() A function type: function
Extended InferJS Types Description
[any]() Allows Any type: any or *
[array]() An array type: []
[infinity]() An infinity number type: Infinity
[nan]() Not a number type: NaN
[arguments]() The arguments object: arguments.
["className"]() A class name: fooClass
["functionName"]() A function name: fooFunction
["errorName"]() An error type: Error or TypeError or errorName

Heading  InferJS-Library: Expectation Checking with Tag [@infer]()

InferJS-Library also allows for extended type checking with the custom @infer tag. Add one or multiple @infer tags to any parameter type. This will allow for narrowing your types down through expectations.

Below is an simple example of @infer:

Fomart for [@infer]():

/**
 * @infer {string} msg {STRING-NOT-EMPTY} - Checks if string is not empty.
 */

The @infer tag is so versatile you can attach it to multiple types in a group and specify multiple narrowing and values to check against, like so:

/**
 * @infer {(number|string)} msg {INT32|STRING-NOT-EMPTY} - Checks if string is not empty and is an integer32.
 * @infer {array} arrname {IN-ARRAY=a,b,c,d,e} - Checks if a,b,c,d is in array.
 * @infer {object} objname {PROPS=id,name} - Checks if objname has properties id and name.
 */

Heading  InferJS-Library: Tag [@infer]() Expectation Types

There are many extended expectation types for narrowing your types down with your @infer tags.

Below is a list of common rule expectation types:

Expectation                                      Description
[STRING-NOT-EMPTY]() Checks if a string is not empty.
[STRING-EMPTY]() Checks if a string is empty.
[IS-BOOL]() Checks if a string is a boolean, true, false, yes, no, on, off, 0, 1.
[BETWEEN]() Checks if number is between two numbers.
[BETWEEN-INCLUSIVE]() Checks if number is between two numbers and including equal to self.
[BETWEEN-BIGINT]() Checks if string is between two big integers.
[BETWEEN-BIGINT-INCLUSIVE]() Checks if a string is between two big integers including equal to self.
[GREATER-THAN]() Checks if value is greater than.
[GREATER-THAN-EQUAL]() Checks if value is greater than equal.
[LESS-THAN]() Checks if value is less than.
[LESS-THAN-EQUAL]() Checks if value is less than equal.
[REGEX]() Checks if matches a regular expression.
[ALPHA]() Checks if alpha characters.
[IS-NUMBER]() Checks if a string is a number.
[IS-BIGINT]() Checks if a string is a bigint.
[IS-NUMERIC]() Checks if a string is numeric.
[ALPHA-NUMERIC]() Checks if a string is alpha numeric.
[IN-ARRAY-CI]() Checks if in array list case insensitive.
[IN-ARRAY]() Checks if in array list case sensitive.
[NOT-IN-ARRAY-CI]() Checks if not in array list case insensitive.
[NOT-IN-ARRAY]() Checks if not in array list case sensitive.
[EXTENDS-ALL]() Checks if object extends all types.
[EXTENDS]() Checks if object extends type.
[PROPS]() Checks if object contains properties.
[ARRAY-NOT-EMPTY]() Checks if array not empty.
[ARRAY-EMPTY]() Checks if array is empty.
[ARRAY-TYPES]() Checks if array items of are of expected types.
[INT8]() Checks for INT8: -128 to 127
[CHAR]() ^
[UINT8]() Checks for UINT8: 0 to 255
[UCHAR]() ^
[UNSIGNED-CHAR]() ^
[INT16]() Checks for INT16: -32768 to 32767
[SHORT]() ^
[SHORT-INT]() ^
[SIGNED-SHORT]() ^
[UINT16]() Check for UINT16: 0 to 65535
[UNSIGNED-SHORT]() ^
[UNSIGNED-SHORT-INT]() ^
[USHORT]() ^
[INT32]() Check for INT32: -2147483648 to 2147483647
[SIGNED-INT]() ^
[INT]() ^
[UINT32]() Check for UINT32: 0 to 4294967295
[UNSIGNED-INT]() ^
[UINT]() ^
[INT64]() Check for INT64: -9223372036854775808 to 9223372036854775807
[SIGNED-LONG]() ^
[SIGNED-LONG-LONG]() ^
[LONG]() ^
[LONG-LONG]() ^
[UINT64]() Check for UINT64: 0 to 18446744073709551615
[UNSIGNED-LONG]() ^
[UNSIGNED-LONG-LONG]() ^
[ULONG]() ^

Heading  InferJS-Library: Linking with Tag [@inferid]()

The tag @inferid is a unique identifier for linking InferJS-Library behind the scenes. It is required for each method, property or field, you would like to check.

This special tag, allows code to still work, while JavaScript is compressed/minified or obfuscated. All Infers are stored in a precompiled InferObject file. This makes it easy to write in your static data types and not have to worry about type checking them during JavaScript Runtime execution.

@inferid can be anything you want as a name, but must be unique per item you want to check.

Below is an example of @inferid:

Fomart for [@inferid]():

/**
 * @inferid foo
 */

Heading  InferJS-Library: Running InferJS Checks with Method [check()]()

To check all your types and expectations, you need to call the InferJS-Library method check(). It needs to be added at the beginning of each method(s) starting closure or below each variable you would like to check.

Below is the overload signature for the method check(): Method Signature for InferJS-Library: check()
check ( inferId: [@inferid](),  args: [arguments](),  returnException: [boolean =]()false )
Description: Type checks all parameters in arguments list and either returns or throws exception.
check ( inferId: [@inferid](),  arg: [field](),  returnException: [boolean =]()false )
Description: Type checks single declared variables or fields.

Example Check All Method Params:

function foo(){
  inferjs.check('Your - @inferid', arguments);
}

Example Check Field or Variable:

var a = 'foo';
inferjs.check('Your - @inferid', a);  

Heading  InferJS Library: Type Checking Errors

In InferJS-Library you have the option to throw or return exception from the check() method. Thrown errors come with tons of information for debugging your types and expectations.

Exception Types Description
InferUnhandledError For all errors unhandled by the InferJS library.
InferTypeError For all type errors created from the JSDoc tag @param {type}
InferExpectError For all errors related to the custom JSDoc tag @infer and custom expectation rules.

Below are examples of exception type responses from InferJS-Library.

> InferTypeError Example:

InferTypeError: Incorrect third parameter type in:
File: /path/to/test1.js
Line: 14
@inferid: foo
@function: ( msg: <string>, id: <number>, objectTester: <object> )
@param: objectTester
Expected Type: object
Actual Type: null

> InferExpectError Example:

InferExpectError: Incorrect first parameter, failed infer expectation type check in:
File: /path/to/test1.js
Line: 14
@inferid: foo
@function: foo( msg: <string|number|null>, id: <number|string>, send: <boolean> )
@param: msg
Expectation Type: STRING-NOT-EMPTY
Expectation Value: "1234"
Argument Value: ""

For more examples, please refer to the Documentation

Heading  InferJS-Library: Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag enhancement. Don't forget to give the project a [⭐ star](), Thanks again!

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Heading  InferJS-Library: License

Distributed under the MIT License. See LICENSE.txt for more information.

Heading  InferJS-Library: Support Related