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.
408 lines
11 KiB
408 lines
11 KiB
|
|
'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;
|
|
|