tagmeme-analyzer

1.2.0 • Public • Published

tagmeme-analyzer

Build Status npm Coverage Status

Static code analyzer and CLI tool for javascript to verify correctness of pattern matching when using tagmeme by andrejewski

The problem

When using tagmeme, you have to define the union cases as strings, here is an example:

import { union } from "tagememe" 
 
const Option = union([ "Some", "None" ])

We are declaring the Option type that can either be Some or None. These two cases are considered constructors when creating a value of the Option type:

const color = Option.Some("green");

Now that we have a value, we can pattern-match against it:

const colorValue = Option.match(color, {
    Some: value => value, 
    None: () => "blue"
})

I really like the API but because this is javascript, it can be very error prone when working with a large application, there are many things can go wrong in runtime causing the match to throw an exception:

  • When forgetting to handle a case (or misspelling the case name)
  • When handling a case that wasn't declared (handling too many cases)
  • When there is a redundant catchAll argument that will never match (see docs)
  • Using match as a union case
  • Using duplicate union cases in the declaration
  • Misspelling the union case when constructing a value

Solution: Static code analysis

Because there are known variables where things could go wrong at "compile" time, why not write a program that checks the correctness of pattern matching? This is what this project provides implemented as a cli tool for easy integration with existing projects:

npm install --save-dev tagmeme-analyzer

Let's see it in action: here is a sample code with the errors that get generated:

{repo}/sample/types.js

import { union as makeUnion } from 'tagmeme'
export const Numbers = makeUnion([ 'One', 'Two', 'match' ]);
export const Option = makeUnion([ 'Some', 'None' ]);
export const Result = makeUnion([ 'Ok', 'Error' ]);
export const Deplicates = makeUnion([ 'First', 'First' ]);

{repo}/sample/app.js

import { Option, Result } from './types'
 
const color = Option.Some('green')
 
// Correct usage, no errors
const colorValue = Option.match(color, {
    Some: colorName => colorName, 
    None: () => 'blue'
});
 
// Incorrect union constructor
const invalid = Option.Nome();
 
// Type name misspelled: 'Option' => 'Opion'
const otherValue = Opion.match(color, {
    Some: colorName => colorName, 
    None: () => 'blue'
});
 
// Error misspelled => 'Erro'
const firstResult = Result.match(Result.Ok('success'), {
    Ok: value => value, 
    Erro: () => 'blue'
});
 
// Handling too many cases, case 'Other' is not declared
const secondResult = Result.match(Result.Ok('success'), {
    Ok: value => value, 
    Error: () => 'blue', 
    Other: () => 'too many cases handled'
});
 
// redundant catchAll argument
const withCatchAll = Option.match(color, {
    Some: colorName => colorName, 
    None: () => 'blue'
}, () => "default-color");

Now running tagmeme-analyzer against {repo}/sample/app.js gives the following:

example

Current Limitations (PRs <=> ❤️)

  • Analyzer runs against one root file (local imports are traversed just to find declarations)
  • Imported union type declarations cannot be aliased
  • Only ES6 exports for now
  • Types of union case data are not checked

Readme

Keywords

none

Package Sidebar

Install

npm i tagmeme-analyzer

Weekly Downloads

0

Version

1.2.0

License

MIT

Unpacked Size

97.2 kB

Total Files

11

Last publish

Collaborators

  • zaid-ajaj