eslint-plugin-css-modules
Version:
Checks that you are using the existent css/scss/less classes, no more no less
135 lines (126 loc) • 16.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _fp = _interopRequireDefault(require("lodash/fp"));
var _lodash = _interopRequireDefault(require("lodash"));
var _path = _interopRequireDefault(require("path"));
var _core = require("../core");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var _default = exports["default"] = {
meta: {
docs: {
description: 'Checks that you are using all css/scss/less classes',
recommended: true
},
schema: [{
type: 'object',
properties: {
camelCase: {
"enum": [true, 'dashes', 'only', 'dashes-only']
},
markAsUsed: {
type: 'array'
}
}
}]
},
create: function create(context) {
var markAsUsed = _lodash["default"].get(context, 'options[0].markAsUsed');
var camelCase = _lodash["default"].get(context, 'options[0].camelCase');
/*
maps variable name to property Object
map = {
[variableName]: {
classes: { foo: false, 'foo-bar': false },
classesMap: { foo: 'foo', fooBar: 'foo-bar', 'foo-bar': 'foo-bar' },
node: {...}
}
}
example:
import s from './foo.scss';
s is variable name
property Object has two keys
1. classes: an object with className as key and a boolean as value. The boolean is marked if it is used in file
2. classesMap: an object with propertyName as key and its className as value
3. node: node that correspond to s (see example above)
*/
var map = {};
return {
ImportDeclaration: function ImportDeclaration(node) {
var styleImportNodeData = (0, _core.getStyleImportNodeData)(node);
if (!styleImportNodeData) {
return;
}
var importName = styleImportNodeData.importName,
styleFilePath = styleImportNodeData.styleFilePath,
importNode = styleImportNodeData.importNode;
var styleFileAbsolutePath = (0, _core.getFilePath)(context, styleFilePath);
var classes = {};
var classesMap = {};
if ((0, _core.fileExists)(styleFileAbsolutePath)) {
// this will be used to mark s.foo as used in MemberExpression
var ast = (0, _core.getAST)(styleFileAbsolutePath);
classes = ast && (0, _core.getStyleClasses)(ast);
classesMap = classes && (0, _core.getClassesMap)(classes, camelCase);
}
_lodash["default"].set(map, "".concat(importName, ".classes"), classes);
_lodash["default"].set(map, "".concat(importName, ".classesMap"), classesMap);
// save node for reporting unused styles
_lodash["default"].set(map, "".concat(importName, ".node"), importNode);
// save file path for reporting unused styles
_lodash["default"].set(map, "".concat(importName, ".filePath"), styleFilePath);
},
MemberExpression: function MemberExpression(node) {
/*
Check if property exists in css/scss file as class
*/
var objectName = node.object.name;
var propertyName = (0, _core.getPropertyName)(node, camelCase);
if (!propertyName) {
return;
}
var className = _lodash["default"].get(map, "".concat(objectName, ".classesMap.").concat(propertyName));
if (className == null) {
return;
}
// mark this property has used
_lodash["default"].set(map, "".concat(objectName, ".classes.").concat(className), true);
},
'Program:exit': function ProgramExit() {
/*
Check if all classes defined in css/scss file are used
*/
/*
we are looping over each import style node in program
example:
```
import s from './foo.css';
import x from './bar.scss';
```
then the loop will be run 2 times
*/
_lodash["default"].forIn(map, function (o) {
var classes = o.classes,
node = o.node,
filePath = o.filePath;
/*
if option is passed to mark a class as used, example:
eslint css-modules/no-unused-class: [2, { markAsUsed: ['container'] }]
*/
_lodash["default"].forEach(markAsUsed, function (usedClass) {
classes[usedClass] = true;
});
// classNames not marked as true are unused
var unusedClasses = _fp["default"].compose(_fp["default"].keys, _fp["default"].omitBy(_fp["default"].identity) // omit truthy values
)(classes);
if (!_lodash["default"].isEmpty(unusedClasses)) {
context.report(node, "Unused classes found in ".concat(_path["default"].basename(filePath), ": ").concat(unusedClasses.join(', ')));
}
});
}
};
}
};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZnAiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9sb2Rhc2giLCJfcGF0aCIsIl9jb3JlIiwib2JqIiwiX19lc01vZHVsZSIsIl9kZWZhdWx0IiwiZXhwb3J0cyIsIm1ldGEiLCJkb2NzIiwiZGVzY3JpcHRpb24iLCJyZWNvbW1lbmRlZCIsInNjaGVtYSIsInR5cGUiLCJwcm9wZXJ0aWVzIiwiY2FtZWxDYXNlIiwibWFya0FzVXNlZCIsImNyZWF0ZSIsImNvbnRleHQiLCJfIiwiZ2V0IiwibWFwIiwiSW1wb3J0RGVjbGFyYXRpb24iLCJub2RlIiwic3R5bGVJbXBvcnROb2RlRGF0YSIsImdldFN0eWxlSW1wb3J0Tm9kZURhdGEiLCJpbXBvcnROYW1lIiwic3R5bGVGaWxlUGF0aCIsImltcG9ydE5vZGUiLCJzdHlsZUZpbGVBYnNvbHV0ZVBhdGgiLCJnZXRGaWxlUGF0aCIsImNsYXNzZXMiLCJjbGFzc2VzTWFwIiwiZmlsZUV4aXN0cyIsImFzdCIsImdldEFTVCIsImdldFN0eWxlQ2xhc3NlcyIsImdldENsYXNzZXNNYXAiLCJzZXQiLCJjb25jYXQiLCJNZW1iZXJFeHByZXNzaW9uIiwib2JqZWN0TmFtZSIsIm9iamVjdCIsIm5hbWUiLCJwcm9wZXJ0eU5hbWUiLCJnZXRQcm9wZXJ0eU5hbWUiLCJjbGFzc05hbWUiLCJQcm9ncmFtRXhpdCIsImZvckluIiwibyIsImZpbGVQYXRoIiwiZm9yRWFjaCIsInVzZWRDbGFzcyIsInVudXNlZENsYXNzZXMiLCJmcCIsImNvbXBvc2UiLCJrZXlzIiwib21pdEJ5IiwiaWRlbnRpdHkiLCJpc0VtcHR5IiwicmVwb3J0IiwicGF0aCIsImJhc2VuYW1lIiwiam9pbiJdLCJzb3VyY2VzIjpbIi4uLy4uL2xpYi9ydWxlcy9uby11bnVzZWQtY2xhc3MuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyogQGZsb3cgKi9cbmltcG9ydCBmcCBmcm9tICdsb2Rhc2gvZnAnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuXG5pbXBvcnQge1xuICBnZXRTdHlsZUltcG9ydE5vZGVEYXRhLFxuICBnZXRTdHlsZUNsYXNzZXMsXG4gIGdldFByb3BlcnR5TmFtZSxcbiAgZ2V0Q2xhc3Nlc01hcCxcbiAgZ2V0RmlsZVBhdGgsXG4gIGdldEFTVCxcbiAgZmlsZUV4aXN0cyxcbn0gZnJvbSAnLi4vY29yZSc7XG5cbmltcG9ydCB0eXBlIHsgSnNOb2RlIH0gZnJvbSAnLi4vdHlwZXMnO1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIG1ldGE6IHtcbiAgICBkb2NzOiB7XG4gICAgICBkZXNjcmlwdGlvbjogJ0NoZWNrcyB0aGF0IHlvdSBhcmUgdXNpbmcgYWxsIGNzcy9zY3NzL2xlc3MgY2xhc3NlcycsXG4gICAgICByZWNvbW1lbmRlZDogdHJ1ZSxcbiAgICB9LFxuICAgIHNjaGVtYTogW1xuICAgICAge1xuICAgICAgICB0eXBlOiAnb2JqZWN0JyxcbiAgICAgICAgcHJvcGVydGllczoge1xuICAgICAgICAgIGNhbWVsQ2FzZTogeyBlbnVtOiBbdHJ1ZSwgJ2Rhc2hlcycsICdvbmx5JywgJ2Rhc2hlcy1vbmx5J10gfSxcbiAgICAgICAgICBtYXJrQXNVc2VkOiB7IHR5cGU6ICdhcnJheScgfSxcbiAgICAgICAgfSxcbiAgICAgIH1cbiAgICBdLFxuICB9LFxuICBjcmVhdGUgKGNvbnRleHQ6IE9iamVjdCkge1xuICAgIGNvbnN0IG1hcmtBc1VzZWQgPSBfLmdldChjb250ZXh0LCAnb3B0aW9uc1swXS5tYXJrQXNVc2VkJyk7XG4gICAgY29uc3QgY2FtZWxDYXNlID0gXy5nZXQoY29udGV4dCwgJ29wdGlvbnNbMF0uY2FtZWxDYXNlJyk7XG5cbiAgICAvKlxuICAgICAgIG1hcHMgdmFyaWFibGUgbmFtZSB0byBwcm9wZXJ0eSBPYmplY3RcbiAgICAgICBtYXAgPSB7XG4gICAgICAgICBbdmFyaWFibGVOYW1lXToge1xuICAgICAgICAgICBjbGFzc2VzOiB7IGZvbzogZmFsc2UsICdmb28tYmFyJzogZmFsc2UgfSxcbiAgICAgICAgICAgY2xhc3Nlc01hcDogeyBmb286ICdmb28nLCBmb29CYXI6ICdmb28tYmFyJywgJ2Zvby1iYXInOiAnZm9vLWJhcicgfSxcbiAgICAgICAgICAgbm9kZTogey4uLn1cbiAgICAgICAgIH1cbiAgICAgICB9XG5cbiAgICAgICBleGFtcGxlOlxuICAgICAgIGltcG9ydCBzIGZyb20gJy4vZm9vLnNjc3MnO1xuICAgICAgIHMgaXMgdmFyaWFibGUgbmFtZVxuXG4gICAgICAgcHJvcGVydHkgT2JqZWN0IGhhcyB0d28ga2V5c1xuICAgICAgIDEuIGNsYXNzZXM6IGFuIG9iamVjdCB3aXRoIGNsYXNzTmFtZSBhcyBrZXkgYW5kIGEgYm9vbGVhbiBhcyB2YWx1ZS4gVGhlIGJvb2xlYW4gaXMgbWFya2VkIGlmIGl0IGlzIHVzZWQgaW4gZmlsZVxuICAgICAgIDIuIGNsYXNzZXNNYXA6IGFuIG9iamVjdCB3aXRoIHByb3BlcnR5TmFtZSBhcyBrZXkgYW5kIGl0cyBjbGFzc05hbWUgYXMgdmFsdWVcbiAgICAgICAzLiBub2RlOiBub2RlIHRoYXQgY29ycmVzcG9uZCB0byBzIChzZWUgZXhhbXBsZSBhYm92ZSlcbiAgICAgKi9cbiAgICBjb25zdCBtYXAgPSB7fTtcblxuICAgIHJldHVybiB7XG4gICAgICBJbXBvcnREZWNsYXJhdGlvbiAobm9kZTogSnNOb2RlKSB7XG4gICAgICAgIGNvbnN0IHN0eWxlSW1wb3J0Tm9kZURhdGEgPSBnZXRTdHlsZUltcG9ydE5vZGVEYXRhKG5vZGUpO1xuXG4gICAgICAgIGlmICghc3R5bGVJbXBvcnROb2RlRGF0YSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBpbXBvcnROYW1lLFxuICAgICAgICAgIHN0eWxlRmlsZVBhdGgsXG4gICAgICAgICAgaW1wb3J0Tm9kZSxcbiAgICAgICAgfSA9IHN0eWxlSW1wb3J0Tm9kZURhdGE7XG5cbiAgICAgICAgY29uc3Qgc3R5bGVGaWxlQWJzb2x1dGVQYXRoID0gZ2V0RmlsZVBhdGgoY29udGV4dCwgc3R5bGVGaWxlUGF0aCk7XG5cbiAgICAgICAgbGV0IGNsYXNzZXMgPSB7fTtcbiAgICAgICAgbGV0IGNsYXNzZXNNYXAgPSB7fTtcblxuICAgICAgICBpZiAoZmlsZUV4aXN0cyhzdHlsZUZpbGVBYnNvbHV0ZVBhdGgpKSB7XG4gICAgICAgICAgLy8gdGhpcyB3aWxsIGJlIHVzZWQgdG8gbWFyayBzLmZvbyBhcyB1c2VkIGluIE1lbWJlckV4cHJlc3Npb25cbiAgICAgICAgICBjb25zdCBhc3QgPSBnZXRBU1Qoc3R5bGVGaWxlQWJzb2x1dGVQYXRoKTtcbiAgICAgICAgICBjbGFzc2VzID0gYXN0ICYmIGdldFN0eWxlQ2xhc3Nlcyhhc3QpO1xuICAgICAgICAgIGNsYXNzZXNNYXAgPSBjbGFzc2VzICYmIGdldENsYXNzZXNNYXAoY2xhc3NlcywgY2FtZWxDYXNlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIF8uc2V0KG1hcCwgYCR7aW1wb3J0TmFtZX0uY2xhc3Nlc2AsIGNsYXNzZXMpO1xuICAgICAgICBfLnNldChtYXAsIGAke2ltcG9ydE5hbWV9LmNsYXNzZXNNYXBgLCBjbGFzc2VzTWFwKTtcblxuICAgICAgICAvLyBzYXZlIG5vZGUgZm9yIHJlcG9ydGluZyB1bnVzZWQgc3R5bGVzXG4gICAgICAgIF8uc2V0KG1hcCwgYCR7aW1wb3J0TmFtZX0ubm9kZWAsIGltcG9ydE5vZGUpO1xuXG4gICAgICAgIC8vIHNhdmUgZmlsZSBwYXRoIGZvciByZXBvcnRpbmcgdW51c2VkIHN0eWxlc1xuICAgICAgICBfLnNldChtYXAsIGAke2ltcG9ydE5hbWV9LmZpbGVQYXRoYCwgc3R5bGVGaWxlUGF0aCk7XG4gICAgICB9LFxuICAgICAgTWVtYmVyRXhwcmVzc2lvbjogKG5vZGU6IEpzTm9kZSkgPT4ge1xuICAgICAgICAvKlxuICAgICAgICAgICBDaGVjayBpZiBwcm9wZXJ0eSBleGlzdHMgaW4gY3NzL3Njc3MgZmlsZSBhcyBjbGFzc1xuICAgICAgICAgKi9cblxuICAgICAgICBjb25zdCBvYmplY3ROYW1lID0gbm9kZS5vYmplY3QubmFtZTtcbiAgICAgICAgY29uc3QgcHJvcGVydHlOYW1lID0gZ2V0UHJvcGVydHlOYW1lKG5vZGUsIGNhbWVsQ2FzZSk7XG5cbiAgICAgICAgaWYgKCFwcm9wZXJ0eU5hbWUpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjbGFzc05hbWUgPSBfLmdldChtYXAsIGAke29iamVjdE5hbWV9LmNsYXNzZXNNYXAuJHtwcm9wZXJ0eU5hbWV9YCk7XG5cbiAgICAgICAgaWYgKGNsYXNzTmFtZSA9PSBudWxsKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gbWFyayB0aGlzIHByb3BlcnR5IGhhcyB1c2VkXG4gICAgICAgIF8uc2V0KG1hcCwgYCR7b2JqZWN0TmFtZX0uY2xhc3Nlcy4ke2NsYXNzTmFtZX1gLCB0cnVlKTtcbiAgICAgIH0sXG4gICAgICAnUHJvZ3JhbTpleGl0JyAoKSB7XG4gICAgICAgIC8qXG4gICAgICAgICAgIENoZWNrIGlmIGFsbCBjbGFzc2VzIGRlZmluZWQgaW4gY3NzL3Njc3MgZmlsZSBhcmUgdXNlZFxuICAgICAgICAgKi9cblxuICAgICAgICAvKlxuICAgICAgICAgICB3ZSBhcmUgbG9vcGluZyBvdmVyIGVhY2ggaW1wb3J0IHN0eWxlIG5vZGUgaW4gcHJvZ3JhbVxuICAgICAgICAgICBleGFtcGxlOlxuICAgICAgICAgICBgYGBcbiAgICAgICAgICAgICBpbXBvcnQgcyBmcm9tICcuL2Zvby5jc3MnO1xuICAgICAgICAgICAgIGltcG9ydCB4IGZyb20gJy4vYmFyLnNjc3MnO1xuICAgICAgICAgICBgYGBcbiAgICAgICAgICAgdGhlbiB0aGUgbG9vcCB3aWxsIGJlIHJ1biAyIHRpbWVzXG4gICAgICAgICAqL1xuICAgICAgICBfLmZvckluKG1hcCwgKG8pID0+IHtcbiAgICAgICAgICBjb25zdCB7IGNsYXNzZXMsIG5vZGUsIGZpbGVQYXRoIH0gPSBvO1xuXG4gICAgICAgICAgLypcbiAgICAgICAgICAgICBpZiBvcHRpb24gaXMgcGFzc2VkIHRvIG1hcmsgYSBjbGFzcyBhcyB1c2VkLCBleGFtcGxlOlxuICAgICAgICAgICAgIGVzbGludCBjc3MtbW9kdWxlcy9uby11bnVzZWQtY2xhc3M6IFsyLCB7IG1hcmtBc1VzZWQ6IFsnY29udGFpbmVyJ10gfV1cbiAgICAgICAgICAgKi9cbiAgICAgICAgICBfLmZvckVhY2gobWFya0FzVXNlZCwgKHVzZWRDbGFzcykgPT4ge1xuICAgICAgICAgICAgY2xhc3Nlc1t1c2VkQ2xhc3NdID0gdHJ1ZTtcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIC8vIGNsYXNzTmFtZXMgbm90IG1hcmtlZCBhcyB0cnVlIGFyZSB1bnVzZWRcbiAgICAgICAgICBjb25zdCB1bnVzZWRDbGFzc2VzID0gZnAuY29tcG9zZShcbiAgICAgICAgICAgIGZwLmtleXMsXG4gICAgICAgICAgICBmcC5vbWl0QnkoZnAuaWRlbnRpdHkpLCAvLyBvbWl0IHRydXRoeSB2YWx1ZXNcbiAgICAgICAgICApKGNsYXNzZXMpO1xuXG4gICAgICAgICAgaWYgKCFfLmlzRW1wdHkodW51c2VkQ2xhc3NlcykpIHtcbiAgICAgICAgICAgIGNvbnRleHQucmVwb3J0KG5vZGUsIGBVbnVzZWQgY2xhc3NlcyBmb3VuZCBpbiAke3BhdGguYmFzZW5hbWUoZmlsZVBhdGgpfTogJHt1bnVzZWRDbGFzc2VzLmpvaW4oJywgJyl9YCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuICB9XG59O1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFDQSxJQUFBQSxHQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxPQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRSxLQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7QUFFQSxJQUFBRyxLQUFB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