UNPKG

prettierx

Version:

prettierX - a less opinionated fork of the Prettier code formatter

216 lines (197 loc) 5.89 kB
"use strict"; const { isBlockComment } = require("./utils"); const ignoredProperties = new Set([ "range", "raw", "comments", "leadingComments", "trailingComments", "innerComments", "extra", "start", "end", "loc", "flags", "errors", "tokens", ]); const removeTemplateElementsValue = (node) => { for (const templateElement of node.quasis) { delete templateElement.value; } }; function clean(ast, newObj, parent) { if (ast.type === "Program") { delete newObj.sourceType; } if ( ast.type === "BigIntLiteral" || ast.type === "BigIntLiteralTypeAnnotation" ) { if (newObj.value) { newObj.value = newObj.value.toLowerCase(); } } if (ast.type === "BigIntLiteral" || ast.type === "Literal") { if (newObj.bigint) { newObj.bigint = newObj.bigint.toLowerCase(); } } if (ast.type === "DecimalLiteral") { newObj.value = Number(newObj.value); } if (ast.type === "Literal" && newObj.decimal) { newObj.decimal = Number(newObj.decimal); } // We remove extra `;` and add them when needed if (ast.type === "EmptyStatement") { return null; } // We move text around, including whitespaces and add {" "} if (ast.type === "JSXText") { return null; } if ( ast.type === "JSXExpressionContainer" && (ast.expression.type === "Literal" || ast.expression.type === "StringLiteral") && ast.expression.value === " " ) { return null; } // We change {'key': value} into {key: value}. // And {key: value} into {'key': value}. // Also for (some) number keys. if ( (ast.type === "Property" || ast.type === "ObjectProperty" || ast.type === "MethodDefinition" || ast.type === "ClassProperty" || ast.type === "ClassMethod" || ast.type === "PropertyDefinition" || ast.type === "TSDeclareMethod" || ast.type === "TSPropertySignature" || ast.type === "ObjectTypeProperty") && typeof ast.key === "object" && ast.key && (ast.key.type === "Literal" || ast.key.type === "NumericLiteral" || ast.key.type === "StringLiteral" || ast.key.type === "Identifier") ) { delete newObj.key; } // Remove raw and cooked values from TemplateElement when it's CSS // styled-jsx if ( ast.type === "JSXElement" && ast.openingElement.name.name === "style" && ast.openingElement.attributes.some((attr) => attr.name.name === "jsx") ) { for (const { type, expression } of newObj.children) { if ( type === "JSXExpressionContainer" && expression.type === "TemplateLiteral" ) { removeTemplateElementsValue(expression); } } } // CSS template literals in css prop if ( ast.type === "JSXAttribute" && ast.name.name === "css" && ast.value.type === "JSXExpressionContainer" && ast.value.expression.type === "TemplateLiteral" ) { removeTemplateElementsValue(newObj.value.expression); } // We change quotes if ( ast.type === "JSXAttribute" && ast.value && ast.value.type === "Literal" && /["']|"|'/.test(ast.value.value) ) { newObj.value.value = newObj.value.value.replace(/["']|"|'/g, '"'); } // Angular Components: Inline HTML template and Inline CSS styles const expression = ast.expression || ast.callee; if ( ast.type === "Decorator" && expression.type === "CallExpression" && expression.callee.name === "Component" && expression.arguments.length === 1 ) { const astProps = ast.expression.arguments[0].properties; for (const [ index, prop, ] of newObj.expression.arguments[0].properties.entries()) { switch (astProps[index].key.name) { case "styles": if (prop.value.type === "ArrayExpression") { removeTemplateElementsValue(prop.value.elements[0]); } break; case "template": if (prop.value.type === "TemplateLiteral") { removeTemplateElementsValue(prop.value); } break; } } } // styled-components, graphql, markdown if ( ast.type === "TaggedTemplateExpression" && (ast.tag.type === "MemberExpression" || (ast.tag.type === "Identifier" && (ast.tag.name === "gql" || ast.tag.name === "graphql" || ast.tag.name === "css" || ast.tag.name === "md" || ast.tag.name === "markdown" || ast.tag.name === "html")) || ast.tag.type === "CallExpression") ) { removeTemplateElementsValue(newObj.quasi); } if (ast.type === "TemplateLiteral") { // This checks for a leading comment that is exactly `/* GraphQL */` // In order to be in line with other implementations of this comment tag // we will not trim the comment value and we will expect exactly one space on // either side of the GraphQL string // Also see ./embed.js const hasLanguageComment = ast.leadingComments && ast.leadingComments.some( (comment) => isBlockComment(comment) && ["GraphQL", "HTML"].some( (languageName) => comment.value === ` ${languageName} ` ) ); if ( hasLanguageComment || (parent.type === "CallExpression" && parent.callee.name === "graphql") || // TODO: check parser // `flow` and `typescript` don't have `leadingComments` !ast.leadingComments ) { removeTemplateElementsValue(newObj); } } if (ast.type === "InterpreterDirective") { newObj.value = newObj.value.trimEnd(); } // Prettier removes degenerate union and intersection types with only one member. if ( (ast.type === "TSIntersectionType" || ast.type === "TSUnionType") && ast.types.length === 1 ) { return newObj.types[0]; } } clean.ignoredProperties = ignoredProperties; module.exports = clean;