All Projects → clausejs → clausejs

clausejs / clausejs

Licence: MIT license
Write contract once. Get data & function validators & conformers, an accurate & readable project contract, auto-generated API documentation, generative test coverage, plus more. A tool that enables a more predictable workflow for developing your JavaScript projects.

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language
shell
77523 projects

Projects that are alternatives of or similar to clausejs

soldoc
A solidity documentation generator, based in NatSpec format. 📃 with standalone HTML, pdf, gitbook and docsify output ✏️ just plug and play.
Stars: ✭ 54 (+86.21%)
Mutual labels:  documentation-tool, docgen
piggy
Test for spec compatibility and breaking changes.
Stars: ✭ 45 (+55.17%)
Mutual labels:  property-based-testing, clojure-spec
cryptaddress.now
A minimal service to detect which cryptocurrency an address corresponds to.
Stars: ✭ 23 (-20.69%)
Mutual labels:  regex
jsdoc-api
A programmatic interface for jsdoc3 with a few extra features
Stars: ✭ 55 (+89.66%)
Mutual labels:  documentation-tool
chappe
🧑‍💻 Developer Docs builder. Write guides in Markdown and references in API Blueprint. Comes with a built-in search engine.
Stars: ✭ 132 (+355.17%)
Mutual labels:  documentation-tool
kuickcheck
A property based testing framework for Kotlin
Stars: ✭ 23 (-20.69%)
Mutual labels:  property-based-testing
django-redirects
↪️ ✅ redirects as they should be, with full control.
Stars: ✭ 32 (+10.34%)
Mutual labels:  regex
pysorter
A command line utility for organizing files and directories according to regex patterns.
Stars: ✭ 40 (+37.93%)
Mutual labels:  regex
logwatch
日志采集工具
Stars: ✭ 22 (-24.14%)
Mutual labels:  regex
stat133-spring-2019
Course materials for Stat 133, Spring 2019, at UC Berkeley
Stars: ✭ 26 (-10.34%)
Mutual labels:  regex
json2python-models
Generate Python model classes (pydantic, attrs, dataclasses) based on JSON datasets with typing module support
Stars: ✭ 119 (+310.34%)
Mutual labels:  typing
defn-spec
Define Clojure specs inline with your function definitions
Stars: ✭ 67 (+131.03%)
Mutual labels:  clojure-spec
pytermgui
Python TUI framework with mouse support, modular widget system, customizable and rapid terminal markup language and more!
Stars: ✭ 1,270 (+4279.31%)
Mutual labels:  typing
expand-brackets
Expand POSIX bracket expressions (character classes) in glob patterns.
Stars: ✭ 26 (-10.34%)
Mutual labels:  regex
kitimat
A library for generative, property-based testing in TypeScript and Jest.
Stars: ✭ 68 (+134.48%)
Mutual labels:  property-based-testing
ocaml-re-nfa
OCaml code to construct an NFA from a regular expression
Stars: ✭ 44 (+51.72%)
Mutual labels:  regex
is-regex
Is this value a JS regex?
Stars: ✭ 22 (-24.14%)
Mutual labels:  regex
erc721
The reference implementation of the ERC-721 non-fungible token standard.
Stars: ✭ 989 (+3310.34%)
Mutual labels:  contract
mdrip
turns markdown into tested tutorials
Stars: ✭ 30 (+3.45%)
Mutual labels:  documentation-tool
java-core
Collections of solutions for micro-tasks created while building modules as part of project. Also has very fun stuffs :)
Stars: ✭ 35 (+20.69%)
Mutual labels:  regex

Clause

If a programming language is regarded as a tool to aid the programmer, it should give him the greatest assistance in the most difficult aspects of his art, namely program design, documentation, and debugging.

C. A. R. Hoare, Hints on Programming Language Design

A powerful, expressive & practical JavaScript library for defining and verifying your JS app contract. Also facilitates with bug discovery, debugging & data parsing.

Build Status npm version Dependencies Size Gzipped Open Source Love Discussion

Overview

Clause enables you to:

  • Build your data validation rules (clauses) with simple predicate functions and composable logical expressions such as and, any, shape, collOf, mapOf, maybe as well as regex-like clause-composing operators such as concatenation(cat), or(|), oneOrMore(+), zeroOrMore(*), zeroOrOne(?), etc
  • Validate and make assertions about your data with your clauses
  • Define complex clauses for your functions' arguments, return value and the relation between them
  • Conform (parse) your data/arguments for writing simpler code
  • Create types that are recursively defined

Clause is heavily inspired by clojure.spec, but will be evolving on its own to better suite the needs of JavaScript community.

Why Clause

Clause's primary goal is to allow you to create the definitive contract for your JavaScript project.

By writing clauses for your data and functions only once, you can get a lot of leverage out your effort, including

  • Clearly defined specifications for your app's functions and data structures
  • Type and behavior checking at runtime for data and functions (some compile-time analysis may also be possible in the future)
  • Convenient data conformation (parsing) that simplifies your code for complex data and parameter parsing
  • Mathematically sound, plain-object style contracts that can be compared against previous and future versions to detect breaking changes (coming soon)
  • Automatic generation of API documentation for your app (via clausejs-docgen, WIP)
  • Automatic generation of property-based test coverage for your functions (via clausejs-gen, coming soon)

Also worth looking at are videos on rationale for clojure.spec (and, by extension, Clause).

Project status

Alpha.

  • Most core functions of Clause have gone through many iterations of bug fixing and are stablizing.
  • Some design aspects, especially API interfaces are still subject to change based on developer feedback.
  • Feedback and suggestions are welcome.

Quick Examples

Regex Ops & conformation

// In browser environment, Clause will by default expose "C" as a global variable
var C = require('clausejs');

var MyClause = C.cat( C.oneOrMore(C.isNum), C.zeroOrOne( C.isObj ) );
C.isValid(MyClause, [ 1, 2, 3, { a: 1 } ]); //=> true
C.isValid(MyClause,  [ 1, 2, 3 ]); //=> true
C.isValid(MyClause,  [ 1, 2, 3, null ]); //=> false: the trailing element does not satisfy our clause
C.isValid(MyClause,  [ 1, 2, 3, { a: 1 }, { } ]); //=> false: extra trailing element
C.conform(MyClause, [ 1, 2, 3, null ]);
//=> a "Problem" object with detailed explanation why validation failed

// Next, we redefine the above concatenation clause, with a label for each part.
var MyLabelledClause = C.cat(
    "myNumbers", C.oneOrMore(C.isNum),
    "myObject", C.zeroOrOne( C.isObj )
  );

MyLabelledClause.conform( [ 1, 2, 3, { a: 1 } ] );
//=> { myNumbers: [ 1, 2, 3 ], myObject: { a: 1 } }

(Notice how the returned results are grouped by the labels specified in the cat clause.)

Clause Registry

// Clause comes with an application-wide global clause registry.
C("myApp/myLabelledClause", MyLabelledClause); // defines a clause in the registry
C("myApp/myLabelledClause"); // returns the same clause above (MyLabelledClause)

Object Shapes

// Before we continue: let's first define a predicate function
// (which is just a function that returns either true or false).
function startsWithBar( str ) {
  return str.indexOf("bar") === 0;
}

// Now let's clauseify a "shape" for our objects.
var MyObjClause = C.shape({
    // alternatively, you can simply provide an array of strings
    // as required keys e.g. [ "propertyA", "propertyB",... ]
    required: {
      // define a single key with value clause
      foo: C.isBool,
      // ...or define a group of properties whose keys satisfy the first clause (e.g. startsWithBar),
      // and whose value satisfies the second (e.g. C.any)
      bars: [ startsWithBar, C.any ]
    },
    optional: {
        // you can also arbitrarily compose new clauses from registered clauses
        myObj: C("myApp/myLabelledClause")
    }
});

// With the above clause defined, now let's try shape conformation.
C.conform( MyObjClause, { foo: true, bar1: 1, bar2: 2, bar3: 3 });
// { foo: true, bars: { bar1: 1, bar2: 2, bar3: 3 } }
// (Notice how all object keys that begin with "bar" are now grouped under a single value "bars").

Function Clauses

// Now onward to function clauses.
var MyFnClause = C.fclause({
  args: MyLabelledClause , // reusing MyClause from above
  ret: C.isBool,
});

// Next we write our function.
function __myFunction(num1, num2, num3, myObj) {
  // doesn't do much; just returns true for now.
  return true;
};

// Then "instrument"(wrap/protect) this function with our function clause.
var myProtectedFn = MyFnClause.instrument(__myFunction);

// We can now try our new protected function.
myProtectedFn(1, 2, 3, { a: true }); // returns true
myProtectedFn(1, 2, 3, 'hello'); // Throws a "Problem" due to mismatched argument per our fclause definition.

// Finally, let's build a function that checks if the sum of all numbers are odd
// by taking advantage of Clause's function argument conformation.

// Step 1: we write a "barebone" function with our core logic,
// which consumes the conformed arguments as a single object.
// This will make sense in a second.
function __sumIsOdd( conformedArgs ) {
  // (Here "conformedArgs" stores the value of the conformed object
  // as we illustrated above.)
  var myNumbers = conformedArgs.myNumbers; // e.g. [ 1, 2, 3 ]
  var myObject = conformedArgs.myObject; // e.g. { a: 1 }
  // (or simply { myNumbers, myObject } with ES6 destructring)

  // Get the sum
  var sum = myNumbers.reduce( function(c,s) { return s + c; }, 0 );

  // Returns whether the sum is odd
  return sum % 2 === 1;
}

// Step 2: wrap the barebone function with C.instrumentConformed()
var sumIsOdd = MyFnClause.instrmentConformed(__sumIsOdd);

// Let's try our new super function!
sumIsOdd( 1, 1, 1 ); //=> true: sum is odd
sumIsOdd( 2, 2, 2 ); //=> false: sum is even
sumIsOdd( 1, 1, 1, {} ); //=> true (remember the optional trailing isObj we defined above?)
sumIsOdd( 2, 2, 2, null ); //=> throws a "Problem" because arguments do not conform
sumIsOdd( 2, 2, 2, {}, {} ); //=> same as above

For more examples (with live demos), advanced features and concepts, refer to documentation site.

More Examples

In addition, there are plenty of examples in test files under /test.

Try It Yourself

Usage

For Node.js/browserify/webpack:

npm install clausejs

For browser:

Include Clause script tag in <head> or <body> tag of your HTML:

<script src="//unpkg.com/clausejs@latest/dist/clausejs.js"></script>

The variable C will be exposed in the global environment (e.g. window for browser and globals for Node.js).

Run tests

In Dev mode

npm run dev

In CI mode

npm run test

Documentation

Documentation website: http://clause.js.org

Performance & Reliability

  • Size Minified Size Gzipped
  • No external dependencies
  • Clause is mostly self-contained and has very few external dependencies.
  • Clause uses NFA algorithm for regex parsing, which means it's generally pretty fast in handling complex regex operations.
  • Clause's implementation is optimized in such a way that it avoid long chains of recursive function calls and makes as few redundant path visits as possible.

Subprojects

WIP:

  • clausejs-docgen: Automatic documentation generation based on function clauses
  • clausejs-react: More robust props validation for your React apps. A replacement for React.PropTypes

Coming soon:

  • clausejs-gen: Generative/Property-based Testing
  • clausejs-diff: (Coming soon) clause version diffing that detects breaking changes.

FAQ

Why not just use ClojureScript + cljs.spec?

Clojure IMO is a great and practical language. If you can use Clojure/ClojureScript, by all means go ahead and try cljs.spec.

The goal for Clause is to provide JavaScript developers as much the benefit derived from the spec system as possible.

Clause API for the most part is kept similar to clojure.spec, except for some differences related to usability and JavaScript-related conventions.

Why don't you call it "spec"?

"Spec" already carries a different meaning in the JavaScript community, which is strongly associated with unit tests. While introducing this library to developers with the term "spec", I was often met with a confused look along with a commment such as "I already know how to write a spec, so what's the point?" I then quickly realized that a new term needs to be coined to refect some of the vastly different concepts introduced in Clause.

Community

Discussion

Prior art & related work

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].