urbit-ob

JavaScript utilities for phonemic base wrangling.
Log | Files | Refs | README

commit 684d007983431abf7a0eb941a9588fb10302258e
parent 60c6b7a6d83f0b1b105f690c3e5243ac8768a2b3
Author: Jared Tobin <jared@jtobin.io>
Date:   Sat,  3 Nov 2018 13:07:52 +1300

Add (weak) validation for @p and @q on conversion.

Functions like patp2hex and patq2hex will now throw on an invalid @p or
@q input.  Note that these checks are not foolproof and only perform a
relatively weak validation, but one that should be sufficient for most
purposes.

Diffstat:
Msrc/internal/co.js | 50++++++++++++++++++++++++++++++++++++++++++--------
Mtest/co.test.js | 22++++++++++++++++++++++
2 files changed, 64 insertions(+), 8 deletions(-)

diff --git a/src/internal/co.js b/src/internal/co.js @@ -52,6 +52,9 @@ remlysfynwerrycsugnysnyllyndyndemluxfedsedbecmun\ lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes\ ` +const patp2syls = name => + name.replace(/[\^~-]/g,'').match(/.{1,3}/g) + const splitAt = (index, str) => [str.slice(0, index), str.slice(index)] const prefixes = pre.match(/.{1,3}/g) @@ -129,14 +132,16 @@ const hex2patp = (hex) => * @return {String} */ const patp2hex = (name) => { - const arr = - name.replace(/[\^~-]/g,'').match(/.{1,3}/g) + if (isValidPat(name) === false) { + throw new Error('patp2hex: not a valid @p') + } + const syls = patp2syls(name) const syl2bin = idx => idx.toString(2).padStart(8, '0') - const addr = lodash.reduce(arr, (acc, syl, idx) => - idx % 2 !== 0 || arr.length === 1 + const addr = lodash.reduce(syls, (acc, syl, idx) => + idx % 2 !== 0 || syls.length === 1 ? acc + syl2bin(suffixes.indexOf(syl)) : acc + syl2bin(prefixes.indexOf(syl)), '') @@ -215,8 +220,11 @@ const hex2patq = hex => * @param {String} name @q * @return {String} */ -const patq2hex = str => { - const chunks = lodash.split(str.slice(1), '-') +const patq2hex = name => { + if (isValidPat(name) === false) { + throw new Error('patq2hex: not a valid @q') + } + const chunks = lodash.split(name.slice(1), '-') const dec2hex = dec => dec.toString(16).padStart(2, '0') @@ -228,7 +236,7 @@ const patq2hex = str => { dec2hex(suffixes.indexOf(syls[1])) }) - return str.length === 0 + return name.length === 0 ? '00' : splat.join('') } @@ -271,7 +279,6 @@ const clan = who => { : 'comet' } - /** * Determine the parent of a @p value. * @@ -294,6 +301,33 @@ const sein = (name) => { return patp(res) } +/** + * Weakly check if a string is a valid @p or @q value. + * + * This is, at present, a pretty weak internal sanity check. It doesn't + * confirm the structure precisely (e.g. dashes), and for @q, it's required + * that q values of (greater than one) odd bytelength have been zero-padded. + * So, for example, '~doznec-binwod' will be considered a valid @q, but + * '~nec-binwod' will not. + * + * @param {String} name a @p or @q value + * @return {String} + */ +const isValidPat = name => { + const syls = patp2syls(name) + + const leadingTilde = name.slice(0, 1) === '~' + const wrongLength = syls.length % 2 !== 0 && syls.length !== 1 + const sylsExist = lodash.reduce(syls, (acc, syl, index) => + acc && + (index % 2 !== 0 || syls.length === 1 + ? suffixes.includes(syl) + : prefixes.includes(syl)), + true) + + return leadingTilde && !wrongLength && sylsExist +} + module.exports = { patp, patp2hex, diff --git a/test/co.test.js b/test/co.test.js @@ -48,6 +48,17 @@ describe('patp, etc.', () => { .to.equal('~divmes-davset-holdet--sallun-salpel-taswet-holtex--watmeb-tarlun-picdet-magmes--holter-dacruc-timdet-divtud--holwet-maldut-padpel-sivtud') }) + it('patp2hex throws on invalid patp', () => { + let input = () => patp2hex('nidsut-tomdun') + expect(input).to.throw() + input = () => patp2hex('~nidsut-tomdzn') + expect(input).to.throw() + input = () => patp2hex('~sut-tomdun') + expect(input).to.throw() + input = () => patp2hex('~nidsut-dun') + expect(input).to.throw() + }) + it('patp and patp2dec are inverses', () => { let iso0 = jsc.forall(jsc.uint32, num => parseInt(patp2dec(patp(num))) === num @@ -98,6 +109,17 @@ describe('patq, etc.', () => { .to.equal('~tastud-holruc-sidwet-salpel-taswet-holdeg-paddec-davdut-holdut-davwex-balwet-divwen-holdet-holruc-taslun-salpel-holtux-dacwex-baltud') }) + it('patq2hex throws on invalid patp', () => { + let input = () => patq2hex('nidsut-tomdun') + expect(input).to.throw() + input = () => patq2hex('~nidsut-tomdzn') + expect(input).to.throw() + input = () => patq2hex('~sut-tomdun') + expect(input).to.throw() + input = () => patq2hex('~nidsut-dun') + expect(input).to.throw() + }) + it('patq and patq2dec are inverses', () => { let iso0 = jsc.forall(jsc.uint32, num => parseInt(patq2dec(patq(num))) === num