UNPKG

@hero-design/snowflake-guard

Version:

A hero-design bot detecting snowflake usage

186 lines (185 loc) 9.78 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const recast = __importStar(require("recast")); const reportClassName_1 = __importDefault(require("./reportClassName")); const reportInlineStyle_1 = __importDefault(require("./reportInlineStyle")); const mapViolatingAttributesAndAdditionalProps = (violatingAttributes, additionalProps) => { return violatingAttributes.map((violatingAttribute) => (Object.assign(Object.assign({}, violatingAttribute), (additionalProps && additionalProps.length ? { additionalProps } : {})))); }; const getNonApprovedInlineLocs = (reportedLocs, violatingAttributes, approvedCmts, elementLoc) => { var _a, _b; const approvedCmt = approvedCmts.find((cmt) => cmt.loc === elementLoc - 1); if (approvedCmt) { const approvedCmtAttrNames = (_b = (_a = approvedCmt.comment .toLowerCase() .replace(/\s+/g, '') .split('attributes:')[1]) === null || _a === void 0 ? void 0 : _a.split(',')) !== null && _b !== void 0 ? _b : []; const noneApprovedStyleAttributes = violatingAttributes.filter((attr) => attr.loc === reportedLocs.style && !approvedCmtAttrNames.includes(attr.attributeName.toLowerCase())); const noneApprovedSxAttributes = violatingAttributes.filter((attr) => attr.loc === reportedLocs.sx && !approvedCmtAttrNames.includes(attr.attributeName.toLowerCase())); if (noneApprovedStyleAttributes.length > 0 || noneApprovedSxAttributes.length > 0) { return { reportedLocs, noneApprovedAttributes: [ ...noneApprovedStyleAttributes, ...noneApprovedSxAttributes, ], }; } return { reportedLocs: {}, noneApprovedAttributes: [] }; } return { reportedLocs, noneApprovedAttributes: violatingAttributes }; }; const reportCustomProperties = (ast, componentList, commentList) => { const report = { className: [], style: [], sx: [], violatingAttributes: [], }; const localComponentList = Object.keys(componentList); recast.visit(ast, { visitJSXOpeningElement(path) { this.traverse(path); // Case 1: Custom default component, e.g. <Card /> if (path.value.name.type === 'JSXIdentifier' && localComponentList.includes(path.value.name.name)) { const attributes = path.value .attributes; const classNameLoc = (0, reportClassName_1.default)(attributes); if (classNameLoc && !commentList.classNameCmts.includes(path.value.loc.start.line - 1)) { report.className.push(classNameLoc); } const { locs: styleObjectLocs, violatingAttributes, additionalProps, } = (0, reportInlineStyle_1.default)(ast, attributes, componentList[path.value.name.name]); const { reportedLocs, noneApprovedAttributes } = getNonApprovedInlineLocs(styleObjectLocs, violatingAttributes, commentList.styleCmts, path.value.loc.start.line); if (reportedLocs.style) { report.style.push(reportedLocs.style); } if (reportedLocs.sx) { report.sx.push(reportedLocs.sx); } report.violatingAttributes = [ ...report.violatingAttributes, ...mapViolatingAttributesAndAdditionalProps(noneApprovedAttributes, additionalProps), ]; } // Case 2: Custom compound component, e.g. <Card.Header /> if (path.value.name.type === 'JSXMemberExpression' && localComponentList.includes(path.value.name.object.name)) { const compoundComponentName = [ componentList[path.value.name.object.name], path.value.name.property.name, ].join('.'); const attributes = path.value .attributes; const classNameLoc = (0, reportClassName_1.default)(attributes); if (classNameLoc && !commentList.classNameCmts.includes(path.value.loc.start.line - 1)) { report.className.push(classNameLoc); } const { locs: styleObjectLocs, violatingAttributes, additionalProps, } = (0, reportInlineStyle_1.default)(ast, attributes, compoundComponentName); const { reportedLocs, noneApprovedAttributes } = getNonApprovedInlineLocs(styleObjectLocs, violatingAttributes, commentList.styleCmts, path.value.loc.start.line); if (reportedLocs.style) { report.style.push(reportedLocs.style); } if (reportedLocs.sx) { report.sx.push(reportedLocs.sx); } report.violatingAttributes = [ ...report.violatingAttributes, ...mapViolatingAttributesAndAdditionalProps(noneApprovedAttributes, additionalProps), ]; } }, // Case 3: Custom compound component with spead operator. e.g. const { Header } = Card, then <Header /> visitVariableDeclaration(path) { this.traverse(path); const declaration = path.value .declarations[0]; if (declaration.init && declaration.init.type === 'Identifier' && localComponentList.includes(declaration.init.name)) { const componentName = declaration.init.name; const { id } = declaration; if (id.type === 'ObjectPattern') { const compoundComponentNames = id.properties .map((prop) => prop.type === 'ObjectProperty' && prop.key.type === 'Identifier' ? prop.key.name : null) .filter((name) => name !== null); recast.visit(ast, { visitJSXOpeningElement(openPath) { this.traverse(openPath); if (openPath.value.name.type === 'JSXIdentifier' && compoundComponentNames.includes(openPath.value.name.name)) { const compoundComponentName = [ componentList[componentName], openPath.value.name.name, ].join('.'); const { attributes } = openPath.value; const classNameLoc = (0, reportClassName_1.default)(attributes); if (classNameLoc && !commentList.classNameCmts.includes(openPath.value.loc.start.line - 1)) { report.className.push(classNameLoc); } const { locs: styleObjectLocs, violatingAttributes, additionalProps, } = (0, reportInlineStyle_1.default)(ast, attributes, compoundComponentName); const { reportedLocs, noneApprovedAttributes } = getNonApprovedInlineLocs(styleObjectLocs, violatingAttributes, commentList.styleCmts, openPath.value.loc.start.line); if (reportedLocs.style) { report.style.push(reportedLocs.style); } if (reportedLocs.sx) { report.sx.push(reportedLocs.sx); } report.violatingAttributes = [ ...report.violatingAttributes, ...mapViolatingAttributesAndAdditionalProps(noneApprovedAttributes, additionalProps), ]; } }, }); } } }, }); return report; }; exports.default = reportCustomProperties;