sass-lint
Version:
All Node Sass linter!
157 lines (146 loc) • 5.44 kB
JavaScript
;
var helpers = require('../helpers');
var properties = require('known-css-properties').all;
// Keep track of our properties we need to skip from the gonzales loop
var skipProps = 0;
/**
* Combine the valid property array and the array of extras into a new array
*
* @param {Array} props - The list of default valid properties
* @param {Array} extras - The user specified list of valid properties
* @returns {Array} Combined list
*/
var getCombinedList = function (props, extras) {
return props.concat(extras);
};
/**
* Combines the base property name with the current property name to correct a full property name
*
* @param {String} baseName - The base property name
* @param {String} name - The property name to append to our base property name
* @returns {String} The constructed property name
*/
var generateName = function (baseName, name) {
return baseName + '-' + name;
};
/**
* Recursive function to build up an array of property names when encountering multiline properties
*
* @param {Object} valBlock - The current block node from within our value
* @param {Object} currentProperty - The current base property name i.e. border-
* @param {Number} propsCounted - The number of properties encountered in our multiline so far
* @returns {Array} Array of objects containing our property and line/col info etc
*/
var buildPartialProperty = function (valBlock, currentProperty) {
var propList = [];
if (valBlock.contains('declaration')) {
valBlock.forEach('declaration', function (node) {
var prop = node.first('property');
var value = node.first('value');
skipProps++;
if (prop && prop.first().is('ident')) {
if (value.contains('block')) {
propList = propList.concat(
buildPartialProperty(value.first('block'),
{
name: generateName(currentProperty.name, prop.first('ident').content)
}
)
);
}
else {
propList.push({
name: generateName(currentProperty.name, prop.first('ident').content),
line: prop.first().start.line,
col: prop.first().start.column
});
}
}
});
}
return propList;
};
module.exports = {
'name': 'no-misspelled-properties',
'defaults': {
'extra-properties': []
},
'detect': function (ast, parser) {
var result = [];
var propertyList = getCombinedList(properties, parser.options['extra-properties']);
ast.traverseByType('declaration', function (node) {
var prop = node.first('property');
// declaration may include custom properties etc, check that prop is defined here
if (!prop) {
return false;
}
// If we've already checked declarations in a multiline we can skip those decs here
if (skipProps) {
skipProps -= 1;
return !skipProps;
}
// make sure our first node within our property is an ident
if (!prop.first() || !prop.first().is('ident')) {
return false;
}
var curProperty = prop.first() && prop.first().is('ident') && prop.first('ident').content;
var value = node.first('value');
var fullProperties = [];
if (value.contains('block')) {
// encountered a multiline property, we should build the property list here
fullProperties = buildPartialProperty(
value.first('block'),
{
name: curProperty,
line: prop.first('ident').start.line,
col: prop.first('ident').start.column
}
);
}
// If we have multiline properties
if (fullProperties.length) {
fullProperties.forEach(function (constrProp) {
// Check if the property exists in our list
if (propertyList.indexOf(constrProp.name) === -1) {
result = helpers.addUnique(result, {
'ruleId': parser.rule.name,
'line': constrProp.line,
'column': constrProp.col,
'message': 'Property `' + constrProp.name + '` appears to be spelled incorrectly',
'severity': parser.severity
});
}
});
}
else if (curProperty && curProperty.length) {
/*
* If our property name contains interpolation we need to make a best guess by using a
* partial string match as we can't be 100% on the context
*/
if (prop.contains('interpolation')) {
if (!helpers.isPartialStringMatch(curProperty, propertyList)) {
result = helpers.addUnique(result, {
'ruleId': parser.rule.name,
'line': node.start.line,
'column': node.start.column,
'message': 'Property `' + curProperty + '` appears to be spelled incorrectly',
'severity': parser.severity
});
}
}
// Otherwise it's just a normal string property name, lets check it here
else if (propertyList.indexOf(curProperty) === -1) {
result = helpers.addUnique(result, {
'ruleId': parser.rule.name,
'line': node.start.line,
'column': node.start.column,
'message': 'Property `' + curProperty + '` appears to be spelled incorrectly',
'severity': parser.severity
});
}
}
return false;
});
return result;
}
};