~kiito/bare-js

JavaScript implementation of BARE message encoding
Added unit tests
Use argparse (npm) for command line utilities
Added Union support, switched to ES6 modules everywhere

refs

master
browse  log 

clone

read-only
https://git.sr.ht/~kiito/bare-js
read/write
git@git.sr.ht:~kiito/bare-js

You can also use your local clone with git send-email.

#bare-js

This is a work-in-progress JavaScript/Node.js implementation of BARE.

The idea is, that the schema converter runs on node.js, while the resulting JavaScript classes should be usable both in the browser and in other javascript environments.

#What is still missing

  • Schema validity and integrity verification
  • Some Conversion error handling

#How to use

#Schema converter

The converter located at converter/bare.js is a runnable node.js script, which takes two arguments: [input, [output]]. If one or both are not given, it will write to stdout, and read from stdin respectively. For now the output is barely formatted, each type gets its own line, some whitespace is added for legibility.

Something to be aware of, is that JavaScript does not like to access a class which is only instantiated later on in the source. Should you define a type and plan to use it in other types, make sure its definition comes before any usage, either in the schema, or by reordering the lines in the output. JS will complain if you do otherwise.

I am thinking about trying to reorder the types in code, but circular dependencies will always need manual intervention, and might not work in JS either way. It would be nice to have, but is rather low priority.

#Resulting module

The output from the converter is a file which only works in conjunction with library/bare.mjs. This file contains all the message conversion logic, whereas the conversion output contains the layout specifics of the types you specified in your schema file.

By default, these two are to be used as ES6 Modules. The benefit of this is, that you do not need to have any of the base type classes in your scope, since they are only needed in the type definitions of the second file. Most browsers support this spec, and so does node.js, if the files end in .mjs.

Should your environment not support this feature, or you don't want to use modules, you can full well remove the import and export statements, and load the two files like regular scripts. (I'm not 100% on this, but you can probably even leave them in)

#Now to the actual how-to for using this in a web page:

If you want to use a bare type in your, say main.js script file, you need to load it as a module: <script type="module" src="main.js"></script>. The basic gist is, that modules do not share a scope, but read the MDN article above for more details.

Then in this file you can use an import statement to either load all your types in an object: import YourName from './path/to/output.js';. Just make sure that the library/bare.mjs file is in the same folder as the output, or edit the import statement to match its location.

Or you can only load some types directly into your scope: import {Address, Point} from './path/to/output.js';. You can even rename them with Type as OtherName inside those brackets, should that matter in your use case.

#A Note on Unions

Sadly it isn't possible to just add a hidden property to every JS object, since there is a possibility of one being frozen (all the primitives are). Therefore this lib needs a wrapper, in the form of the UnionValue class, whenever you want to pack someting into a union, you need to specify its Bare type by putting it inside a UnionType. Since the unpack method also gives you a UnionType, you can just put one into your object from the get go and always expect it to be there.

#A note about Number and 64 bits

Javascript is a wonderful language, and as such it doesn't use an integer type for numbers. Instead, every single number is stored as a double precision float. This limits the usable range of integers to 53 bits, which means the maximum unsigned value is just over 9 quadrillion (10^15).

There is the BitInt type, which allows arbitrarily large integers. But it has limitations; you can't use them in Math functions or beside regular Numbers. Keep this in mind when using the variable length, and the 64 bit integer types, since these return a BigInt by default.

The lib provides safeNumber which will convert a BigInt to Number if it fits into 53 bits, or throw an Error if it does not fit, for when you just need a little more headroom.