UNPKG

@navikt/aksel

Version:

Aksel command line interface. Handles css-imports, codemods and more

220 lines (219 loc) 8.31 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; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = transformer; const legacy_tokens_1 = require("../../../../darkside/config/legacy.tokens"); const ast_1 = require("../../../utils/ast"); const lineterminator_1 = require("../../../utils/lineterminator"); const packageImports_1 = __importStar(require("../../../utils/packageImports")); const propsAffected = ["background", "borderColor", "shadow"]; function transformer(file, api) { const j = api.jscodeshift; const root = j(file.source); const toSourceOptions = (0, lineterminator_1.getLineTerminator)(file.source); if (file.source.includes("TODO: aksel box migration")) { return root.toSource(toSourceOptions); } const localName = (0, ast_1.findComponentImport)({ root, j, name: "Box", packageType: "react", }); if (!localName) { return; } const astElements = root.find(j.JSXElement, { openingElement: { name: { type: "JSXIdentifier", name: localName, }, }, }); const tokenComments = []; for (const astElement of astElements.paths()) { let encounteredUnmigratableProp = false; for (const prop of propsAffected) { (0, ast_1.findProps)({ j, path: astElement, name: prop }).forEach((attr) => { const attrvalue = attr.value.value; if (attrvalue.type === "StringLiteral") { const config = legacy_tokens_1.legacyTokenConfig[attrvalue.value]; if (config === null || config === void 0 ? void 0 : config.replacement) { attrvalue.value = config.replacement; } else { encounteredUnmigratableProp = true; const tokenComment = { prop, token: attrvalue.value, }; if (config === null || config === void 0 ? void 0 : config.comment) { tokenComment.comment = config.comment; } tokenComments.push(tokenComment); } } }); } (0, ast_1.findProps)({ j, path: astElement, name: "borderRadius" }).forEach((attr) => { const attrValue = attr.value.value; if (attrValue.type === "StringLiteral") { /* borderRadius="xlarge" */ attrValue.value = convertBorderRadiusToRadius(attrValue.value); } else if (attrValue.type === "JSXExpressionContainer") { /* borderRadius={{xs: "xlarge", sm: "large"}} */ const expression = attrValue.expression; if (expression.type === "ObjectExpression") { /* xs, md, sm */ expression.properties.forEach((property) => { if (property.type === "ObjectProperty") { if (property.value.type === "StringLiteral") { property.value.value = convertBorderRadiusToRadius(property.value.value); } } }); } } }); if (!encounteredUnmigratableProp) { // TODO: ?? Box -> BoxNew type fail? (but works) astElement.node.openingElement.name.name = "BoxNew"; astElement.node.closingElement.name.name = "BoxNew"; } } const blockComment = createFileComments({ tokenComments }); const importAnalysis = analyzePartialMigration(j, root.toSource(toSourceOptions)); if (importAnalysis === "no new") { // WHY: we do nothing to the import statements if we couldn't migrate any Box } if (importAnalysis === "mixed") { // WHY: mixed Box and BoxNew == we keep old, and add the new import (0, packageImports_1.addPackageImport)({ j, root, packageName: "@navikt/ds-react/Box", specifiers: ["BoxNew"], }); } if (importAnalysis === "all new") { // WHY: when we have only new boxes == we replace the old import with the new one (0, packageImports_1.default)(j, root, { fromImport: "@navikt/ds-react", toImport: "@navikt/ds-react/Box", fromName: "Box", toName: "BoxNew", ignoreAlias: true, }); } const output = `${blockComment ? blockComment + "\n\n" : ""}${root.toSource(toSourceOptions)}`; return output; } const createFileComments = ({ tokenComments, }) => { if (tokenComments.length === 0) { return null; } let constructedComment = "/*\nTODO: aksel box migration:\nCould not migrate the following:\n"; for (const { prop, token, comment } of tokenComments.values()) { constructedComment += ` - ${prop}=${token}\n`; if (comment) { constructedComment += ` - ${comment}\n`; } } constructedComment += "*/"; return constructedComment; }; const analyzePartialMigration = (j, source) => { const root = j(source); const astNewElements = (0, ast_1.findJSXElement)({ root, j, name: "BoxNew", originalName: "BoxNew", }); if (astNewElements.length === 0) { return "no new"; } const localName = (0, ast_1.findComponentImport)({ root, j, name: "Box", packageType: "react", }); if (!localName) { // this should never happen throw new Error('package imports have been tampered with before the package import "step" in the migration'); } const astOldElements = (0, ast_1.findJSXElement)({ root, j, name: localName, originalName: "Box", }); if (astOldElements.length === 0) { return "all new"; } return "mixed"; }; const legacyBorderRadiusNameTokenLookup = { full: "full", xlarge: "12", large: "8", medium: "4", small: "2", }; /** * Takes an old valid border-radius token and returns the new converted radius token * oldValue: "xlarge", "full" * @returns "12", "full" */ function convertBorderRadiusToRadius(oldValue) { const radiusTokens = oldValue.split(" "); const newRadius = []; for (const radiusToken of radiusTokens) { if (radiusToken === "full") { newRadius.push(radiusToken); } else if (!(radiusToken in legacyBorderRadiusNameTokenLookup)) { console.warn(`Possibly invalid radius token found: ${radiusToken}\n`); newRadius.push(radiusToken); } else { newRadius.push(`${legacyBorderRadiusNameTokenLookup[radiusToken]}`); } } return newRadius.join(" "); }