Skip to content

Commit

Permalink
feat(index.js): Add range notation support
Browse files Browse the repository at this point in the history
Resolves issue #1
  • Loading branch information
fabiancook committed Aug 3, 2016
1 parent 0b8d147 commit e71543d
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 3 deletions.
93 changes: 90 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
module.exports = cellref;
module.exports.toA1 = convertR1C1toA1;
module.exports.toR1C1 = convertA1toR1C1;
module.exports.toA1Range = convertRange.bind(null, convertR1C1toA1);
module.exports.toR1C1Range = convertRange.bind(null, convertA1toR1C1);
module.exports.range = convertRange;

/**
* R1C1 pattern
Expand All @@ -22,15 +25,28 @@ var R1C1 = /^R(\d+)C(\d+)$/;

var A1 = /^([A-Z]+)(\d+)$/;


/**
* Range pattern
* @type {RegExp}
*/

var Range = /^([A-Z\d]+)\:([A-Z\d+]+)$/;

/**
* Auto detect notation used and convert to the opposite notation
*
* @param {string} ref
* @param {boolean} [detectRange]
* @returns {string}
* @throws {Error}
*/

function cellref(ref) {
function cellref(ref, detectRange) {
if (detectRange && Range.test(ref)) {
return convertRange(ref, cellref);
}

if (R1C1.test(ref)) {
return convertR1C1toA1(ref);
}
Expand All @@ -42,15 +58,81 @@ function cellref(ref) {
throw new Error('could not detect cell reference notation for ' + ref);
}

/**
* Get a string representation of the cell reference type
*
* @param {string} ref
* @param {string}
* @throws {Error}
*/

function getRefType(ref) {
if (R1C1.test(ref)) {
return 'R1C1';
}
if (A1.test(ref)) {
return 'A1';
}

throw new Error('could not detect cell reference notation for ' + ref);
}

/**
* Auto detect range notation used and convert to the opposite notation
*
* If a converter function is passed it will be used to validate and convert
* the cell reference
*
* @param {string} ref
* @param {function} [converter]
* @returns {string}
* @throws {Error}
*/

function convertRange(ref, converter) {
// When exporting we use bind to set the convert
if (ref instanceof Function) {
var temp = ref;
ref = converter;
converter = temp;
}

if (!Range.test(ref)) {
throw new Error(ref + ' is not a valid range reference');
}

if (!(converter instanceof Function)) {
converter = cellref;
}

var refParts = ref
.split(':');

var typePart1 = getRefType(refParts[0]);
var typePart2 = getRefType(refParts[1]);

if (typePart1 !== typePart2) {
throw new Error('Expected type of of cell reference ' +
refParts[1] + ' to be ' + typePart1 + ', got ' + typePart2);
}

return converter(refParts[0]) + ':' + converter(refParts[1]);
}

/**
* Convert A1 notation to R1C1 notation
*
* @param {string} ref
* @param {boolean} [detectRange]
* @returns {string}
* @throws {Error}
*/

function convertA1toR1C1(ref) {
function convertA1toR1C1(ref, detectRange) {
if (detectRange && Range.test(ref)) {
return convertRange(ref, convertA1toR1C1);
}

if (!A1.test(ref)) {
throw new Error(ref + ' is not a valid A1 cell reference');
}
Expand All @@ -74,11 +156,16 @@ function convertA1toR1C1(ref) {
* Convert R1C1 notation to A1 notation
*
* @param {string} ref
* @param {boolean} [detectRange]
* @returns {string}
* @throws {Error}
*/

function convertR1C1toA1(ref) {
function convertR1C1toA1(ref, detectRange) {
if (detectRange && Range.test(ref)) {
return convertRange(ref, convertR1C1toA1);
}

if (!R1C1.test(ref)) {
throw new Error(ref + ' is not a valid R1C1 cell reference');
}
Expand Down
94 changes: 94 additions & 0 deletions spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,98 @@ describe('cellref', function () {
cellref('InvalidCellRef');
}, Error);
});

it('should convert A1 notation range to R1C1 notation', function() {
cellref.toR1C1('A1:A2', true).should.be.exactly('R1C1:R2C1');
cellref.toR1C1('BU59:BU60', true).should.be.exactly('R59C73:R60C73');
});

it('should convert R1C1 notation range to A1 notation', function() {
cellref.toA1('R1C1:R2C1', true).should.be.exactly('A1:A2');
cellref.toA1('R59C73:R60C73', true).should.be.exactly('BU59:BU60');
});

it('should convert A1 notation range to R1C1 notation', function() {
cellref.toR1C1Range('A1:A2').should.be.exactly('R1C1:R2C1');
cellref.toR1C1Range('BU59:BU60').should.be.exactly('R59C73:R60C73');
});

it('should convert R1C1 notation range to A1 notation', function() {
cellref.toA1Range('R1C1:R2C1').should.be.exactly('A1:A2');
cellref.toA1Range('R59C73:R60C73').should.be.exactly('BU59:BU60');
});

it('should auto detect the notation used and convert to the opposite notation (range)', function () {
cellref('R1C1:R2C1', true).should.be.exactly('A1:A2');
cellref('BU59:BU60', true).should.be.exactly('R59C73:R60C73');
});

it('should auto detect the notation used and convert to the opposite notation (range)', function () {
cellref.range('R1C1:R2C1').should.be.exactly('A1:A2');
cellref.range('BU59:BU60').should.be.exactly('R59C73:R60C73');
});

it('should throw an error if the R1C1 cell reference is invalid (range)', function () {
should.throws(function () {
cellref.toA1('InvalidCellRef:InvalidCellRef', true);
}, Error);
});

it('should throw an error if the R1C1 cell reference is invalid (range, upper)', function () {
should.throws(function () {
cellref.toA1('INVALIDCELLREF:INVALIDCELLREF', true);
}, Error);
});

it('should throw an error if the A1 cell reference is invalid (range, R1C1 given)', function () {
should.throws(function () {
cellref.toR1C1('R1C1:R1C2', true);
}, Error);
});

it('should throw an error if the R1C1 cell reference is invalid (range, A1 given)', function () {
should.throws(function () {
cellref.toA1('A1:A2', true);
}, Error);
});

it('should throw an error if the cell reference types are different', function () {
should.throws(function () {
cellref('A1:R1C2', true);
}, Error);
});

it('should throw an error if one of the reference types are invalid', function () {
should.throws(function () {
cellref('A1:InvalidCellRef', true);
}, Error);
should.throws(function () {
cellref('InvalidCellRef:A2', true);
}, Error);
});

it('should throw an error if the cell range contains more than one range', function () {
should.throws(function () {
cellref('A1:R1C2:R1C2', true);
}, Error);
});

it('should throw an error if the cell range contains more than one range', function () {
should.throws(function () {
cellref('A1:R1C2:R1C2', true);
}, Error);
});

it('should throw an error if an invalid range is given', function () {
should.throws(function () {
cellref.range('A1:R1C2:R1C2');
}, Error);
});

it('should throw an error if an invalid cell reference is given', function () {
should.throws(function () {
cellref.range('A1:INVALIDCELLREF');
}, Error);
});

});

0 comments on commit e71543d

Please sign in to comment.