| #!/usr/bin/env node |
| /** |
| * Copyright (c) HashiCorp, Inc. |
| * SPDX-License-Identifier: MPL-2.0 |
| */ |
| |
| /* eslint-env node */ |
| /** |
| * Codemod to transform Icon component to new API to accomodate FlightIcon |
| * example execution from ui directory -> npx ember-template-recast ./templates -t ./scripts/codemods/icon-transform.js |
| * above will run transform on all files in templates directory |
| */ |
| |
| module.exports = (env) => { |
| const { |
| syntax: { builders }, |
| } = env; |
| const hsSizes = ['s', 'm', 'l', 'xlm', 'xl', 'xxl']; |
| |
| // find attribute by name |
| const findAttribute = (attrs, name) => { |
| for (let i = 0; i < attrs.length; i++) { |
| if (attrs[i].name === name) { |
| return [attrs[i], i, attrs[i].value.chars]; |
| } |
| } |
| return []; |
| }; |
| |
| // possibly a bug with ember-template-recast for multi line components with attributes on their own lines |
| // when removing an attribute the one on the line below will jump to the same line as the previous one |
| // this does not happen when removing the first attribute -- doing so may add unnecessary quotes to the first shifted attribute |
| // example: class="{{foo}}" -> class=""{{foo}}"" |
| const preserveFormatting = (attributes, removeIndex) => { |
| if (removeIndex > 0) { |
| // shift the location of the attributes that appear after the one being removed to preserve formatting |
| for (let i = attributes.length - 1; i > removeIndex; i--) { |
| attributes[i].loc = attributes[i - 1].loc; |
| } |
| } |
| }; |
| |
| // transform structure icon size letter to flight icon supported size |
| const transformSize = (attributes, attrName) => { |
| const [attr, attrIndex, value] = findAttribute(attributes, attrName); |
| |
| if (hsSizes.includes(value)) { |
| if (['s', 'm', 'l'].includes(value)) { |
| // before removing attribute set the location of the remaining attributes |
| preserveFormatting(attributes, attrIndex); |
| // since 16 is the default in the component we can remove the attribute |
| attributes.splice(attrIndex, 1); |
| } else { |
| attr.value = builders.text('24'); |
| // rename attribute |
| if (attrName === '@sizeClass') { |
| attr.name = '@size'; |
| } |
| } |
| } |
| }; |
| |
| return { |
| ElementNode(node) { |
| if (node.tag === 'Icon') { |
| const { attributes } = node; |
| // the inital refactor of the component introduced a sizeClass attribute |
| // this can now be mapped to size and removed |
| transformSize(attributes, '@sizeClass'); |
| // check for old component instances that may still have a letter for size value |
| transformSize(attributes, '@size'); |
| } |
| }, |
| }; |
| }; |