Passed
Pull Request — master (#1)
by thomas
01:07
created

lib/index.js   B

Complexity

Total Complexity 37
Complexity/F 5.29

Size

Lines of Code 182
Function Count 7

Duplication

Duplicated Lines 182
Ratio 100 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 2
c 2
b 1
f 0
nc 2
dl 182
loc 182
rs 8.6
wmc 37
mnd 2
bc 35
fnc 7
bpm 5
cpm 5.2857
noi 3

7 Functions

Rating   Name   Duplication   Size   Complexity  
A index.js ➔ fromWords 3 3 1
C index.js ➔ convert 31 31 7
A index.js ➔ toWords 3 3 1
A index.js ➔ prefixChk 12 12 2
C index.js ➔ decode 51 51 12
B index.js ➔ encode 33 33 6
B index.js ➔ polymodStep 24 24 6

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1 View Code Duplication
'use strict';
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2
3
var BigInteger = require('bigi');
4
var ALPHABET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
5
6
// pre-compute lookup table
7
var SEPARATOR = ':';
8
var CSLEN = 8;
9
var ALPHABET_MAP = {};
10
for (var z = 0; z < ALPHABET.length; z++) {
11
    var x = ALPHABET.charAt(z);
12
    if (ALPHABET_MAP[x] !== undefined) {
13
        throw new TypeError(x + ' is ambiguous');
14
    }
15
    ALPHABET_MAP[x] = z;
16
}
17
18
function polymodStep(pre) {
19
    var b = pre.shiftRight(35);
20
    var mask = BigInteger.fromHex('07ffffffff');
21
22
    var v = pre.and(mask).shiftLeft(new BigInteger('5'));
23
24
    if (b.and(new BigInteger('1')).intValue() > 0) {
25
        v = v.xor(BigInteger.fromHex('98f2bc8e61'));
26
    }
27
    if (b.and(new BigInteger('2')).intValue()) {
28
        v = v.xor(BigInteger.fromHex('79b76d99e2'));
29
    }
30
    if (b.and(new BigInteger('4')).intValue()) {
31
        v = v.xor(BigInteger.fromHex('f33e5fb3c4'));
32
    }
33
    if (b.and(new BigInteger('8')).intValue()) {
34
        v = v.xor(BigInteger.fromHex('ae2eabe2a8'));
35
    }
36
    if (b.and(new BigInteger('16')).intValue()) {
37
        v = v.xor(BigInteger.fromHex('1e4f43e470'));
38
    }
39
40
    return v;
41
}
42
43
function prefixChk(prefix) {
44
    var chk = new BigInteger('1');
45
    for (var i = 0; i < prefix.length; ++i) {
46
        var c = prefix.charCodeAt(i);
47
48
        var mixwith = new BigInteger('' + (c & 0x1f));
49
        chk = polymodStep(chk).xor(mixwith);
50
    }
51
52
    chk = polymodStep(chk);
53
    return chk;
54
}
55
56
function encode(prefix, words) {
57
    // too long?
58
    if (prefix.length + CSLEN + 1 + words.length > 90) {
59
        throw new TypeError('Exceeds Base32 maximum length');
60
    }
61
62
    prefix = prefix.toLowerCase();
63
64
    // determine chk mod
65
    var chk = prefixChk(prefix);
66
    var result = prefix + SEPARATOR;
67
    for (var i = 0; i < words.length; ++i) {
68
        var _x = words[i];
69
        if (_x >>> 5 !== 0) {
70
            throw new Error('Non 5-bit word');
71
        }
72
73
        chk = polymodStep(chk).xor(new BigInteger('' + _x));
74
        result += ALPHABET.charAt(_x);
75
    }
76
77
    for (var _i = 0; _i < CSLEN; ++_i) {
78
        chk = polymodStep(chk);
79
    }
80
    chk = chk.xor(new BigInteger('1'));
81
    for (var _i2 = 0; _i2 < CSLEN; ++_i2) {
82
        var pos = 5 * (CSLEN - 1 - _i2);
83
        var v2 = chk.shiftRight(new BigInteger('' + pos)).and(BigInteger.fromHex('1f'));
84
        result += ALPHABET.charAt(v2.toString(10));
85
    }
86
87
    return result;
88
}
89
90
function decode(str) {
91
    if (str.length < 8) throw new TypeError(str + ' too short');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
92
    if (str.length > 90) throw new TypeError(str + ' too long');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
93
94
    // don't allow mixed case
95
    var lowered = str.toLowerCase();
96
    var uppered = str.toUpperCase();
97
    if (str !== lowered && str !== uppered) {
98
        throw new Error('Mixed-case string ' + str);
99
    }
100
101
    str = lowered;
102
103
    var split = str.lastIndexOf(SEPARATOR);
104
    if (split === -1) {
105
        throw new Error('No separator character for ' + str);
106
    }
107
108
    if (split === 0) {
109
        throw new Error('Missing prefix for ' + str);
110
    }
111
112
    var prefix = str.slice(0, split);
113
    var wordChars = str.slice(split + 1);
114
    if (wordChars.length < 6) {
115
        throw new Error('Data too short');
116
    }
117
118
    var chk = prefixChk(prefix);
119
    var words = [];
120
    for (var i = 0; i < wordChars.length; ++i) {
121
        var c = wordChars.charAt(i);
122
        var v = ALPHABET_MAP[c];
123
        if (v === undefined) {
124
            throw new Error('Unknown character ' + c);
125
        }
126
127
        chk = polymodStep(chk).xor(new BigInteger('' + v));
128
        // not in the checksum?
129
        if (i + CSLEN >= wordChars.length) {
130
            continue;
131
        }
132
        words.push(v);
133
    }
134
135
    if (chk.toString(10) !== '1') {
136
        throw new Error('Invalid checksum for ' + str);
137
    }
138
139
    return { prefix: prefix, words: words };
140
}
141
142
function convert(data, inBits, outBits, pad) {
143
    var value = 0;
144
    var bits = 0;
145
    var maxV = (1 << outBits) - 1;
146
147
    var result = [];
148
    for (var i = 0; i < data.length; ++i) {
149
        value = value << inBits | data[i];
150
        bits += inBits;
151
152
        while (bits >= outBits) {
153
            bits -= outBits;
154
            result.push(value >>> bits & maxV);
155
        }
156
    }
157
158
    if (pad) {
159
        if (bits > 0) {
160
            result.push(value << outBits - bits & maxV);
161
        }
162
    } else {
163
        if (bits >= inBits) {
164
            throw new Error('Excess padding');
165
        }
166
        if (value << outBits - bits & maxV) {
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
167
            throw new Error('Non-zero padding');
168
        }
169
    }
170
171
    return result;
172
}
173
174
function toWords(bytes) {
175
    return convert(bytes, 8, 5, true);
176
}
177
178
function fromWords(words) {
179
    return convert(words, 5, 8, false);
180
}
181
182
module.exports = { decode: decode, encode: encode, toWords: toWords, fromWords: fromWords };
183