This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
409 lines
11 KiB
409 lines
11 KiB
6 years ago
|
|
||
|
'use strict';
|
||
|
|
||
|
/**
|
||
|
* StyleSheets represents the StyleSheets found in the source code.
|
||
|
* @constructor
|
||
|
*/
|
||
|
function StyleSheets() {
|
||
|
this.styleSheets = {};
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add adds a StyleSheet to our StyleSheets collections.
|
||
|
*
|
||
|
* @param {string} styleSheetName - The name of the StyleSheet.
|
||
|
* @param {object} properties - The collection of rules in the styleSheet.
|
||
|
*/
|
||
|
StyleSheets.prototype.add = function (styleSheetName, properties) {
|
||
|
this.styleSheets[styleSheetName] = properties;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* MarkAsUsed marks a rule as used in our source code by removing it from the
|
||
|
* specified StyleSheet rules.
|
||
|
*
|
||
|
* @param {string} fullyQualifiedName - The fully qualified name of the rule.
|
||
|
* for example 'styles.text'
|
||
|
*/
|
||
|
StyleSheets.prototype.markAsUsed = function (fullyQualifiedName) {
|
||
|
const nameSplit = fullyQualifiedName.split('.');
|
||
|
const styleSheetName = nameSplit[0];
|
||
|
const styleSheetProperty = nameSplit[1];
|
||
|
|
||
|
if (this.styleSheets[styleSheetName]) {
|
||
|
this.styleSheets[styleSheetName] = this
|
||
|
.styleSheets[styleSheetName]
|
||
|
.filter(property => property.key.name !== styleSheetProperty);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* GetUnusedReferences returns all collected StyleSheets and their
|
||
|
* unmarked rules.
|
||
|
*/
|
||
|
StyleSheets.prototype.getUnusedReferences = function () {
|
||
|
return this.styleSheets;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* AddColorLiterals adds an array of expressions that contain color literals
|
||
|
* to the ColorLiterals collection
|
||
|
* @param {array} expressions - an array of expressions containing color literals
|
||
|
*/
|
||
|
StyleSheets.prototype.addColorLiterals = function (expressions) {
|
||
|
if (!this.colorLiterals) {
|
||
|
this.colorLiterals = [];
|
||
|
}
|
||
|
this.colorLiterals = this.colorLiterals.concat(expressions);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* GetColorLiterals returns an array of collected color literals expressions
|
||
|
* @returns {Array}
|
||
|
*/
|
||
|
StyleSheets.prototype.getColorLiterals = function () {
|
||
|
return this.colorLiterals;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* AddObjectexpressions adds an array of expressions to the ObjectExpressions collection
|
||
|
* @param {Array} expressions - an array of expressions containing ObjectExpressions in
|
||
|
* inline styles
|
||
|
*/
|
||
|
StyleSheets.prototype.addObjectExpressions = function (expressions) {
|
||
|
if (!this.objectExpressions) {
|
||
|
this.objectExpressions = [];
|
||
|
}
|
||
|
this.objectExpressions = this.objectExpressions.concat(expressions);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* GetObjectExpressions returns an array of collected object expressiosn used in inline styles
|
||
|
* @returns {Array}
|
||
|
*/
|
||
|
StyleSheets.prototype.getObjectExpressions = function () {
|
||
|
return this.objectExpressions;
|
||
|
};
|
||
|
|
||
|
|
||
|
let currentContent;
|
||
|
const getSourceCode = node => currentContent
|
||
|
.getSourceCode(node)
|
||
|
.getText(node);
|
||
|
|
||
|
const astHelpers = {
|
||
|
containsStyleSheetObject: function (node) {
|
||
|
return Boolean(
|
||
|
node &&
|
||
|
node.init &&
|
||
|
node.init.callee &&
|
||
|
node.init.callee.object &&
|
||
|
node.init.callee.object.name === 'StyleSheet'
|
||
|
);
|
||
|
},
|
||
|
|
||
|
containsCreateCall: function (node) {
|
||
|
return Boolean(
|
||
|
node &&
|
||
|
node.init &&
|
||
|
node.init.callee &&
|
||
|
node.init.callee.property &&
|
||
|
node.init.callee.property.name === 'create'
|
||
|
);
|
||
|
},
|
||
|
|
||
|
isStyleSheetDeclaration: function (node) {
|
||
|
return Boolean(
|
||
|
astHelpers.containsStyleSheetObject(node) &&
|
||
|
astHelpers.containsCreateCall(node)
|
||
|
);
|
||
|
},
|
||
|
|
||
|
getStyleSheetName: function (node) {
|
||
|
if (
|
||
|
node &&
|
||
|
node.id
|
||
|
) {
|
||
|
return node.id.name;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getStyleDeclarations: function (node) {
|
||
|
if (
|
||
|
node &&
|
||
|
node.init &&
|
||
|
node.init.arguments &&
|
||
|
node.init.arguments[0] &&
|
||
|
node.init.arguments[0].properties
|
||
|
) {
|
||
|
return node
|
||
|
.init
|
||
|
.arguments[0]
|
||
|
.properties
|
||
|
.filter(property => property.type === 'Property');
|
||
|
}
|
||
|
|
||
|
return [];
|
||
|
},
|
||
|
|
||
|
isStyleAttribute: function (node) {
|
||
|
return Boolean(
|
||
|
node.type === 'JSXAttribute' &&
|
||
|
node.name &&
|
||
|
node.name.name &&
|
||
|
node.name.name.toLowerCase().includes('style')
|
||
|
);
|
||
|
},
|
||
|
|
||
|
collectStyleObjectExpressions: function (node, context) {
|
||
|
currentContent = context;
|
||
|
if (astHelpers.hasArrayOfStyleReferences(node)) {
|
||
|
const styleReferenceContainers = node
|
||
|
.expression
|
||
|
.elements;
|
||
|
|
||
|
return astHelpers.collectStyleObjectExpressionFromContainers(
|
||
|
styleReferenceContainers
|
||
|
);
|
||
|
} else if (node && node.expression) {
|
||
|
return astHelpers.getStyleObjectExpressionFromNode(node.expression);
|
||
|
}
|
||
|
|
||
|
return [];
|
||
|
},
|
||
|
|
||
|
collectColorLiterals: function (node, context) {
|
||
|
if (!node) {
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
currentContent = context;
|
||
|
if (astHelpers.hasArrayOfStyleReferences(node)) {
|
||
|
const styleReferenceContainers = node
|
||
|
.expression
|
||
|
.elements;
|
||
|
|
||
|
return astHelpers.collectColorLiteralsFromContainers(
|
||
|
styleReferenceContainers
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (node.type === 'ObjectExpression') {
|
||
|
return astHelpers.getColorLiteralsFromNode(node);
|
||
|
}
|
||
|
|
||
|
return astHelpers.getColorLiteralsFromNode(node.expression);
|
||
|
},
|
||
|
|
||
|
collectStyleObjectExpressionFromContainers: function (nodes) {
|
||
|
let objectExpressions = [];
|
||
|
nodes.forEach((node) => {
|
||
|
objectExpressions = objectExpressions
|
||
|
.concat(astHelpers.getStyleObjectExpressionFromNode(node));
|
||
|
});
|
||
|
|
||
|
return objectExpressions;
|
||
|
},
|
||
|
|
||
|
collectColorLiteralsFromContainers: function (nodes) {
|
||
|
let colorLiterals = [];
|
||
|
nodes.forEach((node) => {
|
||
|
colorLiterals = colorLiterals
|
||
|
.concat(astHelpers.getColorLiteralsFromNode(node));
|
||
|
});
|
||
|
|
||
|
return colorLiterals;
|
||
|
},
|
||
|
|
||
|
getStyleReferenceFromNode: function (node) {
|
||
|
let styleReference;
|
||
|
let leftStyleReferences;
|
||
|
let rightStyleReferences;
|
||
|
|
||
|
if (!node) {
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
switch (node.type) {
|
||
|
case 'MemberExpression':
|
||
|
styleReference = astHelpers.getStyleReferenceFromExpression(node);
|
||
|
return [styleReference];
|
||
|
case 'LogicalExpression':
|
||
|
leftStyleReferences = astHelpers.getStyleReferenceFromNode(node.left);
|
||
|
rightStyleReferences = astHelpers.getStyleReferenceFromNode(node.right);
|
||
|
return [].concat(leftStyleReferences).concat(rightStyleReferences);
|
||
|
case 'ConditionalExpression':
|
||
|
leftStyleReferences = astHelpers.getStyleReferenceFromNode(node.consequent);
|
||
|
rightStyleReferences = astHelpers.getStyleReferenceFromNode(node.alternate);
|
||
|
return [].concat(leftStyleReferences).concat(rightStyleReferences);
|
||
|
default:
|
||
|
return [];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getStyleObjectExpressionFromNode: function (node) {
|
||
|
let leftStyleObjectExpression;
|
||
|
let rightStyleObjectExpression;
|
||
|
|
||
|
if (!node) {
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
if (node.type === 'ObjectExpression') {
|
||
|
return [astHelpers.getStyleObjectFromExpression(node)];
|
||
|
}
|
||
|
|
||
|
switch (node.type) {
|
||
|
case 'LogicalExpression':
|
||
|
leftStyleObjectExpression = astHelpers.getStyleObjectExpressionFromNode(node.left);
|
||
|
rightStyleObjectExpression = astHelpers.getStyleObjectExpressionFromNode(node.right);
|
||
|
return [].concat(leftStyleObjectExpression).concat(rightStyleObjectExpression);
|
||
|
case 'ConditionalExpression':
|
||
|
leftStyleObjectExpression = astHelpers.getStyleObjectExpressionFromNode(node.consequent);
|
||
|
rightStyleObjectExpression = astHelpers.getStyleObjectExpressionFromNode(node.alternate);
|
||
|
return [].concat(leftStyleObjectExpression).concat(rightStyleObjectExpression);
|
||
|
default:
|
||
|
return [];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getColorLiteralsFromNode: function (node) {
|
||
|
let leftColorLiterals;
|
||
|
let rightColorLiterals;
|
||
|
|
||
|
if (!node) {
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
if (node.type === 'ObjectExpression') {
|
||
|
return [astHelpers.getColorLiteralsFromExpression(node)];
|
||
|
}
|
||
|
|
||
|
switch (node.type) {
|
||
|
case 'LogicalExpression':
|
||
|
leftColorLiterals = astHelpers.getColorLiteralsFromNode(node.left);
|
||
|
rightColorLiterals = astHelpers.getColorLiteralsFromNode(node.right);
|
||
|
return [].concat(leftColorLiterals).concat(rightColorLiterals);
|
||
|
case 'ConditionalExpression':
|
||
|
leftColorLiterals = astHelpers.getColorLiteralsFromNode(node.consequent);
|
||
|
rightColorLiterals = astHelpers.getColorLiteralsFromNode(node.alternate);
|
||
|
return [].concat(leftColorLiterals).concat(rightColorLiterals);
|
||
|
default:
|
||
|
return [];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
hasArrayOfStyleReferences: function (node) {
|
||
|
return node && Boolean(
|
||
|
node.type === 'JSXExpressionContainer' &&
|
||
|
node.expression &&
|
||
|
node.expression.type === 'ArrayExpression'
|
||
|
);
|
||
|
},
|
||
|
|
||
|
getStyleReferenceFromExpression: function (node) {
|
||
|
const result = [];
|
||
|
const name = astHelpers.getObjectName(node);
|
||
|
if (name) {
|
||
|
result.push(name);
|
||
|
}
|
||
|
|
||
|
const property = astHelpers.getPropertyName(node);
|
||
|
if (property) {
|
||
|
result.push(property);
|
||
|
}
|
||
|
|
||
|
return result.join('.');
|
||
|
},
|
||
|
|
||
|
getStyleObjectFromExpression: function (node) {
|
||
|
const obj = {};
|
||
|
let invalid = false;
|
||
|
if (node.properties && node.properties.length) {
|
||
|
node.properties.forEach((p) => {
|
||
|
if (!p.value || !p.key) {
|
||
|
return;
|
||
|
}
|
||
|
if (p.value.type === 'Literal') {
|
||
|
invalid = true;
|
||
|
obj[p.key.name] = p.value.value;
|
||
|
} else if (p.value.type === 'ConditionalExpression') {
|
||
|
const innerNode = p.value;
|
||
|
if (innerNode.consequent.type === 'Literal' || innerNode.alternate.type === 'Literal') {
|
||
|
invalid = true;
|
||
|
obj[p.key.name] = getSourceCode(innerNode);
|
||
|
}
|
||
|
} else if (p.value.type === 'UnaryExpression' && p.value.operator === '-') {
|
||
|
invalid = true;
|
||
|
obj[p.key.name] = -1 * p.value.argument.value;
|
||
|
} else if (p.value.type === 'UnaryExpression' && p.value.operator === '+') {
|
||
|
invalid = true;
|
||
|
obj[p.key.name] = p.value.argument.value;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
return invalid ? { expression: obj, node: node } : undefined;
|
||
|
},
|
||
|
|
||
|
getColorLiteralsFromExpression: function (node) {
|
||
|
const obj = {};
|
||
|
let invalid = false;
|
||
|
if (node.properties && node.properties.length) {
|
||
|
node.properties.forEach((p) => {
|
||
|
if (p.key && p.key.name && p.key.name.toLowerCase().indexOf('color') !== -1) {
|
||
|
if (p.value.type === 'Literal') {
|
||
|
invalid = true;
|
||
|
obj[p.key.name] = p.value.value;
|
||
|
} else if (p.value.type === 'ConditionalExpression') {
|
||
|
const innerNode = p.value;
|
||
|
if (innerNode.consequent.type === 'Literal' || innerNode.alternate.type === 'Literal') {
|
||
|
invalid = true;
|
||
|
obj[p.key.name] = getSourceCode(innerNode);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
return invalid ? { expression: obj, node: node } : undefined;
|
||
|
},
|
||
|
|
||
|
getObjectName: function (node) {
|
||
|
if (
|
||
|
node &&
|
||
|
node.object &&
|
||
|
node.object.name
|
||
|
) {
|
||
|
return node.object.name;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getPropertyName: function (node) {
|
||
|
if (
|
||
|
node &&
|
||
|
node.property &&
|
||
|
node.property.name
|
||
|
) {
|
||
|
return node.property.name;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getPotentialStyleReferenceFromMemberExpression: function (node) {
|
||
|
if (
|
||
|
node &&
|
||
|
node.object &&
|
||
|
node.object.type === 'Identifier' &&
|
||
|
node.object.name &&
|
||
|
node.property &&
|
||
|
node.property.type === 'Identifier' &&
|
||
|
node.property.name &&
|
||
|
node.parent.type !== 'MemberExpression'
|
||
|
) {
|
||
|
return [node.object.name, node.property.name].join('.');
|
||
|
}
|
||
|
},
|
||
|
};
|
||
|
|
||
|
module.exports.astHelpers = astHelpers;
|
||
|
module.exports.StyleSheets = StyleSheets;
|