stylelint-processor-glamorous
Version:
Lint glamorous and related css-in-js with stylelint
161 lines (132 loc) • 6.19 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var t = _interopRequireWildcard(require("@babel/types"));
var _traverse = _interopRequireDefault(require("@babel/traverse"));
var _generator = _interopRequireDefault(require("@babel/generator"));
var _postcss = _interopRequireDefault(require("postcss"));
var _postcssJs = _interopRequireDefault(require("postcss-js"));
var _json = _interopRequireDefault(require("json5"));
var _shortid = _interopRequireDefault(require("shortid"));
var _helpers = require("./helpers");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
var sourceMap;
var _default = function _default(ast) {
sourceMap = new Map();
var glamorousImport;
var rules = [];
(0, _traverse.default)(ast, {
enter(path) {
if ((0, _helpers.isCssAttribute)(path) || (0, _helpers.isAnnotatedExpression)(path)) {
rules = rules.concat([path]);
}
if (path.isImportDeclaration()) {
if (path.node.source.value === 'glamorous') {
glamorousImport = path.get('specifiers').filter(function (specifier) {
return specifier.isImportDefaultSpecifier();
})[0];
}
}
if (path.isCallExpression()) {
var importName;
if (glamorousImport) {
importName = glamorousImport.node.local.name;
}
var _path$node$callee = path.node.callee,
object = _path$node$callee.object,
callee = _path$node$callee.callee;
if (object && (object.name === importName || object.name === 'styled') || callee && (callee.name === importName || callee.name === 'styled')) {
path.get('arguments').forEach(function (arg) {
if (arg.isObjectExpression()) {
rules = rules.concat([arg]);
} else if (arg.isFunction()) {
if (arg.get('body').isObjectExpression()) {
rules = rules.concat(arg.get('body'));
} else {
var rule = Object.assign({}, t.objectExpression((0, _helpers.extractDeclarations)(arg.get('body'))), {
loc: path.node.loc
});
path.replaceWith(rule);
rules = rules.concat(path);
}
}
});
}
}
}
});
var styles = [];
rules.forEach(function (rule) {
sourceMap.set(sourceMap.size + 1, rule.node.loc.start);
processRule(rule);
var cssString = getCssString(rule.node);
styles = styles.concat([`.${_shortid.default.generate()}{${cssString && '\n'}${cssString}}`]);
});
return {
css: styles.join('\n'),
sourceMap
};
};
exports.default = _default;
var processRule = function processRule(path) {
if (path.get('properties')) {
path.get('properties').forEach(function (prop) {
if (prop.isObjectProperty() && !(0, _helpers.hasLeadingComment)(prop, /^\s*stylelint-disable-next-line\s*$/)) {
sourceMap.set(sourceMap.size + 1, prop.node.key.loc.start);
if (!prop.get('key').isIdentifier() && !prop.get('key').isStringLiteral()) {
prop.replaceWith(t.objectProperty(t.stringLiteral(`.${_shortid.default.generate()}`), prop.node.value));
} else if (prop.node.key.value) {
// hyphenate strings like minWidth and @fontFace
prop.get('key').replaceWith(t.stringLiteral(prop.node.key.value.replace(/([A-Z])/, '-$1').toLowerCase()));
if (!prop.get('value').isObjectExpression()) {
prop.get('value').replaceWith(t.objectExpression([]));
}
}
if (prop.get('value').isObjectExpression()) {
processRule(prop.get('value'));
} else if (!prop.get('value').isNumericLiteral() && !prop.get('value').isStringLiteral()) {
var values = (0, _helpers.extractValues)(prop.get('value'));
if (prop.get('value').isConditionalExpression() && values.length > 0) {
// Create multiple declarations for conditional expressions.
// Example: { color: prop.primary ? 'red' : 'blue' }
// will be replaced with { color: 'red', color: 'blue'}
var declarations = values.map(function (value, index) {
var key = Object.assign({}, // Attach a random id to the prop so it becomes valid js.
t.stringLiteral(`${prop.node.key.name}$${_shortid.default.generate()}`), {
loc: prop.node.loc
});
if (index > 0) {
sourceMap.set(sourceMap.size + 1, prop.node.key.loc.start);
}
return t.objectProperty(key, value);
});
prop.replaceWithMultiple(declarations);
} else {
prop.get('value').replaceWith(t.stringLiteral('placeholderValue'));
}
}
} else {
prop.node.leadingComments = []; // eslint-disable-line
prop.remove();
}
});
}
};
var getCssString = function getCssString(node) {
try {
var extractedCss = (0, _postcss.default)().process(_json.default.parse((0, _generator.default)(node).code), {
parser: _postcssJs.default
}).css;
return extractedCss && // Collapse closing braces to the end of the last declaration in the block. Makes
// generating the source map a lot easier: simply map every object property to a line in the css.
extractedCss.replace(/\n\s*(?=\s*})/g, '') // Remove Indentations
.replace(/\n\s*/g, '\n') // Remove random id if present
.replace(/(\$.*)(?=.*:)/g, '');
} catch (e) {
e.message = `Parsing Failed. Make sure you're not using unsupported syntax. ${e.message}`;
throw e;
}
};