(function(exports) {
var combineRegExp = (typeof require == 'undefined')
? exports.combineRegExp
: require('./sg-regex-tools').combineRegExp
var SheetParser = exports.SheetParser
var Property = SheetParser.Property = {version: '0.2 dev'};
Finds optional groups in expressions and builds keyword indecies for them. Keyword index is an object that has keywords as keys and values as property names.
Index only holds keywords that can be uniquely identified as one of the properties in group.
Property.index = function(properties, context) {
var index = {};
for (var i = 0, property; property = properties[i]; i++) {
if (property.push) {
var group = index[i] = {};
for (var j = 0, prop; prop = property[j]; j++) {
var keys = context[prop].keywords;
if (keys) for (var key in keys) {
if (group[key] == null) group[key] = prop;
else group[key] = false;
}
}
for (var keyword in group) if (!group[keyword]) delete group[keyword];
}
}
return index;
};
Simple value
Property.simple = function(types, keywords) {
return function(value) {
if (keywords && keywords[value]) return true;
if (types) for (var i = 0, type; type = types[i++];) if (Type[type](value)) return true;
return false;
}
};
Links list of inambigous arguments with corresponding properties keeping the order.
Property.shorthand = function(properties, keywords, context) {
var index, r = 0;
for (var i = 0, property; property = properties[i++];) if (!property.push) r++;
return function() {
var result = [], used = {}, start = 0, group, k = 0, l = arguments.length;
for (var i = 0, argument; argument = arguments[i]; i++) {
var property = properties[k];
if (!property) return false;
if ((group = (property.push && property))) property = properties[k + 1];
if (property) {
if (context[property](argument)) k++
else property = false
}
if (group) {
if (!property) {
if (!index) index = Property.index(properties, context)
if (property = index[k][argument])
if (used[property]) return false;
else used[property] = 1;
}
if ((property && !used[property]) || (i == l - 1)) {
if (i - start > group.length) return false;
for (var j = start; j < (i + +!property); j++)
if (!result[j])
for (var m = 0, optional; optional = group[m++];) {
if (!used[optional] && context[optional](arguments[j])) {
result[j] = optional;
used[optional] = true
break;
}
}
start = i;
k++;
}
}
if (result[i] == null) result[i] = property;
}
if (i < r) return false
for (var i = 0, j = arguments.length, object = {}; i < j; i++) {
var value = result[i];
if (!value) return false;
object[value] = arguments[i];
}
return object;
};
}
A shorthand that operates on collection of properties. When given values are not enough (less than properties in collection), the value sequence is repeated until all properties are filled.
Property.collection = function(properties, keywords, context) {
var first = context[properties[0]];
if (first.type != 'simple')
return function(arg) {
var args = (!arg || !arg.push) ? [Array.prototype.slice.call(arguments)] : arguments;
var length = args.length;
var result = {};
for (var i = 0, property; property = properties[i]; i++) {
var values = context[property].apply(1, args[i] || args[i % 2] || args[0]);
if (!values) return false;
for (var prop in values) result[prop] = values[prop];
}
return result;
}
else
return function() {
var length = arguments.length;
var result = {};
for (var i = 0, property; property = properties[i]; i++) {
var values = arguments[i] || arguments[i % 2] || arguments[0];
if (!context[property].call(1, values)) return false;
result[property] = values;
}
return result;
}
};
Multiple value property accepts arrays as arguments as well as regular stuff
Property.multiple = function(arg) {
if (arg.push)
}
Property.compile = function(definition, context) {
var properties, keywords, types;
for (var i = 0, bit; bit = definition[i++];) {
if (bit.push) properties = bit;
else if (bit.indexOf) {
if (!Type[bit]) {
if (!keywords) keywords = {};
keywords[bit] = 1;
} else types ? types.push(bit) : (types = [bit]);
} else options = bit;
}
var type = properties ? (keywords && keywords.collection ? "collection" : "shorthand") : 'simple'
var property = Property[type](properties || types, keywords, context);
if (keywords) property.keywords = keywords;
if (properties) {
var props = [];
for (var i = 0, prop; prop = properties[i++];) prop.push ? props.push.apply(props, prop) : props.push(prop);
property.properties = props;
}
property.type = type;
return property;
};
var Type = Property.Type = {
length: function(obj) {
return typeof obj == 'number' || (!obj.indexOf && ('number' in obj) && obj.unit && (obj.unit != '%'))
},
color: function(obj) {
return obj.indexOf ? obj.match(/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/) : (obj.isColor || obj.rgba || obj.rgb || obj.hsb)
},
number: function(obj) {
return typeof obj == 'number'
},
integer: function(obj) {
return obj % 1 == 0 && ((0 + obj).toString() == obj)
},
keyword: function(keywords) {
var storage;
for (var i = 0, keyword; keyword = keywords[i++];) storage[keyword] = 1;
return function(keyword) {
return !!storage[keyword]
}
},
strings: function(obj) {
return !!obj.indexOf
},
url: function(obj) {
return !obj.indexOf && ("url" in obj);
},
position: function(obj) {
var positions = Type.position.positions;
if (!positions) positions = Type.position.positions = {left: 1, top: 1, bottom: 1, right: 1, center: 1}
return positions[obj]
},
percentage: function(obj) {
return obj.unit == '%'
}
};
})(typeof exports != 'undefined' ? exports : this);