From 0c6c9abe7a6f09c211d371d0fafb9f5f9ff2737e Mon Sep 17 00:00:00 2001
From: martimalek <46452321+martimalek@users.noreply.github.com>
Date: Tue, 29 Aug 2023 17:44:51 +0200
Subject: [PATCH] Create codemod to migrate colors to css variables (#363)
* chore: bump jscodeshift to 0.15.0
* test: cover block property transform
* feat: replace colors in template string for css vars
* fix: adapt codemod to cover templates with an even number of quasis
* chore: add single quote config option to block codemod
* build: include codemods in build
* docs: add new codemod info in migrating docs
* docs: add semantic tokens recommendation in migration docs
* feat: pass print options to block codemod
---
.eslintignore | 2 +
codemods/v2.ts | 68 ----
docs/migrating.storybook.mdx | 41 ++-
package-lock.json | 334 +-----------------
package.json | 5 +-
.../block-to-width-100.input.tsx | 8 +
.../block-to-width-100.output.tsx | 8 +
.../color-in-JSX-multi-import.input.tsx | 5 +
.../color-in-JSX-multi-import.output.tsx | 5 +
.../color-in-JSX-single-import.input.tsx | 9 +
.../color-in-JSX-single-import.output.tsx | 7 +
.../template-multi-quasis-even.input.tsx | 25 ++
.../template-multi-quasis-even.output.tsx | 25 ++
.../template-multi-quasis-odd.input.tsx | 28 ++
.../template-multi-quasis-odd.output.tsx | 28 ++
.../template-single-quasis.input.tsx | 6 +
.../template-single-quasis.output.tsx | 5 +
.../__tests__/block-to-width-100-test.ts | 6 +
.../__tests__/colors-to-css-vars-test.ts | 18 +
src/codemods/block-to-width-100.ts | 59 ++++
src/codemods/colors-to-css-vars.ts | 159 +++++++++
tsconfig.json | 2 +-
22 files changed, 451 insertions(+), 402 deletions(-)
delete mode 100644 codemods/v2.ts
create mode 100644 src/codemods/__testfixtures__/block-to-width-100.input.tsx
create mode 100644 src/codemods/__testfixtures__/block-to-width-100.output.tsx
create mode 100644 src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-multi-import.input.tsx
create mode 100644 src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-multi-import.output.tsx
create mode 100644 src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-single-import.input.tsx
create mode 100644 src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-single-import.output.tsx
create mode 100644 src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-even.input.tsx
create mode 100644 src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-even.output.tsx
create mode 100644 src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-odd.input.tsx
create mode 100644 src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-odd.output.tsx
create mode 100644 src/codemods/__testfixtures__/colors-to-css-vars/template-single-quasis.input.tsx
create mode 100644 src/codemods/__testfixtures__/colors-to-css-vars/template-single-quasis.output.tsx
create mode 100644 src/codemods/__tests__/block-to-width-100-test.ts
create mode 100644 src/codemods/__tests__/colors-to-css-vars-test.ts
create mode 100644 src/codemods/block-to-width-100.ts
create mode 100644 src/codemods/colors-to-css-vars.ts
diff --git a/.eslintignore b/.eslintignore
index 1cd74997d..dfccc9844 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -12,3 +12,5 @@ assets/
fixtures/
src/icons/
+
+src/codemods/
\ No newline at end of file
diff --git a/codemods/v2.ts b/codemods/v2.ts
deleted file mode 100644
index 145fb5193..000000000
--- a/codemods/v2.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { API, Collection, FileInfo, JSCodeshift } from 'jscodeshift';
-
-function transformBlockProperty(j: JSCodeshift, ast: Collection) {
- const localButtonNames = [];
-
- const fullWidthProp = {
- type: 'JSXAttribute',
- name: 'width',
- value: {
- type: 'StringLiteral',
- value: '100%'
- }
- };
-
- ast
- .find(j.ImportDeclaration, decl => decl.source.value === '@freenow/wave')
- .forEach(decl => {
- j(decl)
- .find(j.ImportSpecifier)
- .forEach(spec => {
- if (spec.node.imported.name === 'Button' || spec.node.imported.name === 'TextButton') {
- localButtonNames.push(spec.node.local.name);
- }
- });
- });
-
- ast
- .find(j.JSXElement, {
- openingElement: {
- name: {
- name: name => {
- return localButtonNames.includes(name);
- }
- }
- }
- })
- .forEach(el => {
- j(el)
- .find(j.JSXAttribute, {
- name: name => {
- return name.name === 'block';
- }
- })
- .forEach(attr => {
- if (attr.value.value) {
- j(attr).find(j.Literal).forEach((literal) => {
- if (literal.value.value === false) {
- j(attr).remove();
- } else {
- j(attr).replaceWith(fullWidthProp);
- }
- });
- } else {
- j(attr).replaceWith(fullWidthProp);
- }
- });
- });
-}
-
-
-module.exports = (file: FileInfo, api: API) => {
- const j = api.jscodeshift;
- const ast = j(file.source);
-
- transformBlockProperty(j, ast)
-
- return ast.toSource()
-};
diff --git a/docs/migrating.storybook.mdx b/docs/migrating.storybook.mdx
index 3c267c3d2..ced28dba1 100644
--- a/docs/migrating.storybook.mdx
+++ b/docs/migrating.storybook.mdx
@@ -4,20 +4,7 @@ import { Meta } from '@storybook/blocks';
# Migrating
-Migrating from one major version to the next with ease.
-
-## From v1 to v2
-
-A codemod exists to upgrade your components for this version.
-
-```bash
-npx jscodeshift -t node_modules/@freenow/wave/codemods/v2.ts path/to/src
-```
-
-### Button and TextButton
-
-The `block` property used to act as a shortcut to give the button components a width of 100%. In the future, use the `width` property
-directly. It uses the styled-system variable, which is a lot more flexible than just the boolean flag.
+Migrate to the next Wave major version with ease.
## Codemods
@@ -28,3 +15,29 @@ previous major versions first. Beware that codemods are not 100% fool-proof and
If you're working in a typescript environment, you need to add `--parser=tsx` to the command in each codemod command to
allow jscodeshift to parse your typescript/jsx files.
+
+## From v1 to v2
+
+Two codemods exist to upgrade your components for version 2. In order to apply the transformations in your project you simply need to run the
+command for your desired codemod pointing to your project's source path.
+
+### Button and TextButton block property
+
+The `block` property used to act as a shortcut to give the button components a width of 100%. In the future, use the `width` property
+directly. It uses the styled-system variable, which is a lot more flexible than just the boolean flag.
+
+```bash
+npx jscodeshift -t node_modules/@freenow/wave/lib/cjs/codemods/block-to-width-100.js path/to/src
+```
+
+### Colors to CSS variables
+
+Our theme colors structure has changed significantly in this major. In order to use Wave colors in your project you should now use the CSS variables
+that our theme brings.
+
+```bash
+npx jscodeshift -t node_modules/@freenow/wave/lib/cjs/codemods/colors-to-css-vars.js path/to/src
+```
+
+Disclaimer: This codemod transforms usages of `Colors` to our bare colors CSS variables to ensure we don't introduce breaking changes, that being said,
+we recommend using semantic tokens instead as a best practice and offer a `getSemanticValue` API for just that.
diff --git a/package-lock.json b/package-lock.json
index ce4be7140..586c44f0d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -50,7 +50,7 @@
"@types/babel__traverse": "7.17.1",
"@types/jest": "^25.1.4",
"@types/jest-axe": "^3.2.1",
- "@types/jscodeshift": "^0.11.1",
+ "@types/jscodeshift": "^0.11.6",
"@types/node": "^17.0.41",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
@@ -76,7 +76,7 @@
"jest-axe": "^3.4.0",
"jest-date-mock": "^1.0.8",
"jest-styled-components": "^7.0.2",
- "jscodeshift": "^0.13.0",
+ "jscodeshift": "^0.15.0",
"minimatch": "^3.0.4",
"prettier": "^2.0.2",
"pretty-quick": "^2.0.1",
@@ -22451,9 +22451,9 @@
}
},
"node_modules/jscodeshift": {
- "version": "0.13.1",
- "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.13.1.tgz",
- "integrity": "sha512-lGyiEbGOvmMRKgWk4vf+lUrCWO/8YR8sUR3FKF1Cq5fovjZDlIcw3Hu5ppLHAnEXshVffvaM0eyuY/AbOeYpnQ==",
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.15.0.tgz",
+ "integrity": "sha512-t337Wx7Vy1ffhas7E1KZUHaR9YPdeCfxPvxz9k6DKwYW88pcs1piR1eR9d+7GQZGSQIZd6a+cfIM3XpMe9rFKQ==",
"dev": true,
"dependencies": {
"@babel/core": "^7.13.16",
@@ -22469,10 +22469,10 @@
"chalk": "^4.1.2",
"flow-parser": "0.*",
"graceful-fs": "^4.2.4",
- "micromatch": "^3.1.10",
+ "micromatch": "^4.0.4",
"neo-async": "^2.5.0",
"node-dir": "^0.1.17",
- "recast": "^0.20.4",
+ "recast": "^0.23.1",
"temp": "^0.8.4",
"write-file-atomic": "^2.3.0"
},
@@ -22481,6 +22481,11 @@
},
"peerDependencies": {
"@babel/preset-env": "^7.1.6"
+ },
+ "peerDependenciesMeta": {
+ "@babel/preset-env": {
+ "optional": true
+ }
}
},
"node_modules/jscodeshift/node_modules/ansi-styles": {
@@ -22498,27 +22503,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/jscodeshift/node_modules/braces": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
- "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
- "dev": true,
- "dependencies": {
- "arr-flatten": "^1.1.0",
- "array-unique": "^0.3.2",
- "extend-shallow": "^2.0.1",
- "fill-range": "^4.0.0",
- "isobject": "^3.0.1",
- "repeat-element": "^1.1.2",
- "snapdragon": "^0.8.1",
- "snapdragon-node": "^2.0.1",
- "split-string": "^3.0.2",
- "to-regex": "^3.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/jscodeshift/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -22553,21 +22537,6 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
- "node_modules/jscodeshift/node_modules/fill-range": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
- "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
- "dev": true,
- "dependencies": {
- "extend-shallow": "^2.0.1",
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1",
- "to-regex-range": "^2.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/jscodeshift/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -22577,118 +22546,6 @@
"node": ">=8"
}
},
- "node_modules/jscodeshift/node_modules/is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
- "dev": true
- },
- "node_modules/jscodeshift/node_modules/is-extendable": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
- "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
- "dev": true,
- "dependencies": {
- "is-plain-object": "^2.0.4"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/jscodeshift/node_modules/is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
- "dev": true,
- "dependencies": {
- "kind-of": "^3.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/jscodeshift/node_modules/is-number/node_modules/kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
- "dev": true,
- "dependencies": {
- "is-buffer": "^1.1.5"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/jscodeshift/node_modules/kind-of": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
- "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/jscodeshift/node_modules/micromatch": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
- "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
- "dev": true,
- "dependencies": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "braces": "^2.3.1",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "extglob": "^2.0.4",
- "fragment-cache": "^0.2.1",
- "kind-of": "^6.0.2",
- "nanomatch": "^1.2.9",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/jscodeshift/node_modules/micromatch/node_modules/extend-shallow": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
- "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
- "dev": true,
- "dependencies": {
- "assign-symbols": "^1.0.0",
- "is-extendable": "^1.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/jscodeshift/node_modules/recast": {
- "version": "0.20.5",
- "resolved": "https://registry.npmjs.org/recast/-/recast-0.20.5.tgz",
- "integrity": "sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==",
- "dev": true,
- "dependencies": {
- "ast-types": "0.14.2",
- "esprima": "~4.0.0",
- "source-map": "~0.6.1",
- "tslib": "^2.0.1"
- },
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/jscodeshift/node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/jscodeshift/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -22701,25 +22558,6 @@
"node": ">=8"
}
},
- "node_modules/jscodeshift/node_modules/to-regex-range": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
- "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
- "dev": true,
- "dependencies": {
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/jscodeshift/node_modules/tslib": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
- "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
- "dev": true
- },
"node_modules/jscodeshift/node_modules/write-file-atomic": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
@@ -50929,9 +50767,9 @@
}
},
"jscodeshift": {
- "version": "0.13.1",
- "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.13.1.tgz",
- "integrity": "sha512-lGyiEbGOvmMRKgWk4vf+lUrCWO/8YR8sUR3FKF1Cq5fovjZDlIcw3Hu5ppLHAnEXshVffvaM0eyuY/AbOeYpnQ==",
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.15.0.tgz",
+ "integrity": "sha512-t337Wx7Vy1ffhas7E1KZUHaR9YPdeCfxPvxz9k6DKwYW88pcs1piR1eR9d+7GQZGSQIZd6a+cfIM3XpMe9rFKQ==",
"dev": true,
"requires": {
"@babel/core": "^7.13.16",
@@ -50947,10 +50785,10 @@
"chalk": "^4.1.2",
"flow-parser": "0.*",
"graceful-fs": "^4.2.4",
- "micromatch": "^3.1.10",
+ "micromatch": "^4.0.4",
"neo-async": "^2.5.0",
"node-dir": "^0.1.17",
- "recast": "^0.20.4",
+ "recast": "^0.23.1",
"temp": "^0.8.4",
"write-file-atomic": "^2.3.0"
},
@@ -50964,24 +50802,6 @@
"color-convert": "^2.0.1"
}
},
- "braces": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
- "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
- "dev": true,
- "requires": {
- "arr-flatten": "^1.1.0",
- "array-unique": "^0.3.2",
- "extend-shallow": "^2.0.1",
- "fill-range": "^4.0.0",
- "isobject": "^3.0.1",
- "repeat-element": "^1.1.2",
- "snapdragon": "^0.8.1",
- "snapdragon-node": "^2.0.1",
- "split-string": "^3.0.2",
- "to-regex": "^3.0.1"
- }
- },
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -51007,116 +50827,12 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
- "fill-range": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
- "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
- "dev": true,
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1",
- "to-regex-range": "^2.1.0"
- }
- },
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
- "dev": true
- },
- "is-extendable": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
- "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
- "dev": true,
- "requires": {
- "is-plain-object": "^2.0.4"
- }
- },
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
- "dev": true,
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
- "dev": true,
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "kind-of": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
- "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
- "dev": true
- },
- "micromatch": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
- "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
- "dev": true,
- "requires": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "braces": "^2.3.1",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "extglob": "^2.0.4",
- "fragment-cache": "^0.2.1",
- "kind-of": "^6.0.2",
- "nanomatch": "^1.2.9",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.2"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
- "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
- "dev": true,
- "requires": {
- "assign-symbols": "^1.0.0",
- "is-extendable": "^1.0.1"
- }
- }
- }
- },
- "recast": {
- "version": "0.20.5",
- "resolved": "https://registry.npmjs.org/recast/-/recast-0.20.5.tgz",
- "integrity": "sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==",
- "dev": true,
- "requires": {
- "ast-types": "0.14.2",
- "esprima": "~4.0.0",
- "source-map": "~0.6.1",
- "tslib": "^2.0.1"
- }
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
- },
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -51126,22 +50842,6 @@
"has-flag": "^4.0.0"
}
},
- "to-regex-range": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
- "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
- "dev": true,
- "requires": {
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1"
- }
- },
- "tslib": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
- "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
- "dev": true
- },
"write-file-atomic": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
diff --git a/package.json b/package.json
index 053b09f27..964234075 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"test": "jest",
"test:fixture": "./scripts/run_fixtures.sh",
"test:watch": "jest --watch",
+ "test:codemods": "jest codemods",
"lint": "npx concurrently \"npm run lint:eslint\" \"npm run lint:stylelint\"",
"lint:stylelint": "stylelint --config .stylelintrc 'src/**/*.ts?(x)'",
"lint:eslint": "eslint --format pretty --ext .js,.jsx,.ts,.tsx src/",
@@ -79,7 +80,7 @@
"@types/babel__traverse": "7.17.1",
"@types/jest": "^25.1.4",
"@types/jest-axe": "^3.2.1",
- "@types/jscodeshift": "^0.11.1",
+ "@types/jscodeshift": "^0.11.6",
"@types/node": "^17.0.41",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
@@ -105,7 +106,7 @@
"jest-axe": "^3.4.0",
"jest-date-mock": "^1.0.8",
"jest-styled-components": "^7.0.2",
- "jscodeshift": "^0.13.0",
+ "jscodeshift": "^0.15.0",
"minimatch": "^3.0.4",
"prettier": "^2.0.2",
"pretty-quick": "^2.0.1",
diff --git a/src/codemods/__testfixtures__/block-to-width-100.input.tsx b/src/codemods/__testfixtures__/block-to-width-100.input.tsx
new file mode 100644
index 000000000..88d862eb7
--- /dev/null
+++ b/src/codemods/__testfixtures__/block-to-width-100.input.tsx
@@ -0,0 +1,8 @@
+import { Button } from '@freenow/wave';
+import React from 'react';
+
+export const ButtonTest = (): JSX.Element => (
+
+);
diff --git a/src/codemods/__testfixtures__/block-to-width-100.output.tsx b/src/codemods/__testfixtures__/block-to-width-100.output.tsx
new file mode 100644
index 000000000..c1833e9b6
--- /dev/null
+++ b/src/codemods/__testfixtures__/block-to-width-100.output.tsx
@@ -0,0 +1,8 @@
+import { Button } from '@freenow/wave';
+import React from 'react';
+
+export const ButtonTest = (): JSX.Element => (
+
+);
diff --git a/src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-multi-import.input.tsx b/src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-multi-import.input.tsx
new file mode 100644
index 000000000..6cf25eab2
--- /dev/null
+++ b/src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-multi-import.input.tsx
@@ -0,0 +1,5 @@
+import { CloseIcon, Colors } from '@freenow/wave';
+
+export const CloseIconWrapper = () => (
+
+);
diff --git a/src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-multi-import.output.tsx b/src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-multi-import.output.tsx
new file mode 100644
index 000000000..147508193
--- /dev/null
+++ b/src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-multi-import.output.tsx
@@ -0,0 +1,5 @@
+import { CloseIcon } from '@freenow/wave';
+
+export const CloseIconWrapper = () => (
+
+);
diff --git a/src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-single-import.input.tsx b/src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-single-import.input.tsx
new file mode 100644
index 000000000..aafd4aa12
--- /dev/null
+++ b/src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-single-import.input.tsx
@@ -0,0 +1,9 @@
+import { Colors } from '@freenow/wave';
+
+export const GhostIcon = () => (
+
+);
diff --git a/src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-single-import.output.tsx b/src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-single-import.output.tsx
new file mode 100644
index 000000000..b66b7cc48
--- /dev/null
+++ b/src/codemods/__testfixtures__/colors-to-css-vars/color-in-JSX-single-import.output.tsx
@@ -0,0 +1,7 @@
+export const GhostIcon = () => (
+
+);
diff --git a/src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-even.input.tsx b/src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-even.input.tsx
new file mode 100644
index 000000000..019f79ab1
--- /dev/null
+++ b/src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-even.input.tsx
@@ -0,0 +1,25 @@
+import { Button, Colors, Spaces } from '@freenow/wave';
+import styled from 'styled-components';
+
+interface Props {
+ label: string;
+ disabled?: boolean;
+ onClick: () => void;
+}
+
+const Action = styled(Button)`
+ justify-content: flex-start;
+
+ color: ${Colors.AUTHENTIC_BLUE_900};
+ font-weight: normal;
+ line-height: 1.43;
+
+ border-radius: 0;
+ padding: ${Spaces[2]};
+`;
+
+export const ActionItem = ({ label, onClick, disabled = false }: Props): JSX.Element => (
+
+ {label}
+
+);
diff --git a/src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-even.output.tsx b/src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-even.output.tsx
new file mode 100644
index 000000000..b79c5221c
--- /dev/null
+++ b/src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-even.output.tsx
@@ -0,0 +1,25 @@
+import { Button, Spaces } from '@freenow/wave';
+import styled from 'styled-components';
+
+interface Props {
+ label: string;
+ disabled?: boolean;
+ onClick: () => void;
+}
+
+const Action = styled(Button)`
+ justify-content: flex-start;
+
+ color: var(--wave-b-color-blue-primary-900);
+ font-weight: normal;
+ line-height: 1.43;
+
+ border-radius: 0;
+ padding: ${Spaces[2]};
+`;
+
+export const ActionItem = ({ label, onClick, disabled = false }: Props): JSX.Element => (
+
+ {label}
+
+);
diff --git a/src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-odd.input.tsx b/src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-odd.input.tsx
new file mode 100644
index 000000000..db9579054
--- /dev/null
+++ b/src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-odd.input.tsx
@@ -0,0 +1,28 @@
+import { Colors, Spaces, TextButton, TextButtonProps } from '@freenow/wave';
+import styled from 'styled-components';
+
+export const NavigationLink: React.FC = styled(TextButton)<{ active: boolean }>`
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+
+ width: 100%;
+
+ padding: ${Spaces[2]};
+ padding-left: ${({ active }) => (active ? '20px' : Spaces[3])};
+
+ font-size: 14px;
+ font-weight: normal;
+ text-decoration: none;
+
+ ${props =>
+ props.active &&
+ `
+ border-left: 4px solid ${Colors.ACTION_BLUE_900};
+ `}
+
+ :hover :first-of-type {
+ text-decoration: none;
+ color: ${Colors.ACTION_BLUE_900};
+ }
+`;
diff --git a/src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-odd.output.tsx b/src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-odd.output.tsx
new file mode 100644
index 000000000..10f95e96a
--- /dev/null
+++ b/src/codemods/__testfixtures__/colors-to-css-vars/template-multi-quasis-odd.output.tsx
@@ -0,0 +1,28 @@
+import { Spaces, TextButton, TextButtonProps } from '@freenow/wave';
+import styled from 'styled-components';
+
+export const NavigationLink: React.FC = styled(TextButton)<{ active: boolean }>`
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+
+ width: 100%;
+
+ padding: ${Spaces[2]};
+ padding-left: ${({ active }) => (active ? '20px' : Spaces[3])};
+
+ font-size: 14px;
+ font-weight: normal;
+ text-decoration: none;
+
+ ${props =>
+ props.active &&
+ `
+ border-left: 4px solid var(--wave-b-color-blue-secondary-900);
+ `}
+
+ :hover :first-of-type {
+ text-decoration: none;
+ color: var(--wave-b-color-blue-secondary-900);
+ }
+`;
diff --git a/src/codemods/__testfixtures__/colors-to-css-vars/template-single-quasis.input.tsx b/src/codemods/__testfixtures__/colors-to-css-vars/template-single-quasis.input.tsx
new file mode 100644
index 000000000..73ba30fb5
--- /dev/null
+++ b/src/codemods/__testfixtures__/colors-to-css-vars/template-single-quasis.input.tsx
@@ -0,0 +1,6 @@
+import { Colors } from '@freenow/wave';
+import styled from 'styled-components';
+
+export const GreyList = styled.ul`
+ color: ${Colors.AUTHENTIC_BLUE_550};
+`;
diff --git a/src/codemods/__testfixtures__/colors-to-css-vars/template-single-quasis.output.tsx b/src/codemods/__testfixtures__/colors-to-css-vars/template-single-quasis.output.tsx
new file mode 100644
index 000000000..3d6f0afc8
--- /dev/null
+++ b/src/codemods/__testfixtures__/colors-to-css-vars/template-single-quasis.output.tsx
@@ -0,0 +1,5 @@
+import styled from 'styled-components';
+
+export const GreyList = styled.ul`
+ color: var(--wave-b-color-blue-primary-550);
+`;
diff --git a/src/codemods/__tests__/block-to-width-100-test.ts b/src/codemods/__tests__/block-to-width-100-test.ts
new file mode 100644
index 000000000..e4aefa652
--- /dev/null
+++ b/src/codemods/__tests__/block-to-width-100-test.ts
@@ -0,0 +1,6 @@
+// import { defineTest } from 'jscodeshift/dist/testUtils'
+
+jest.autoMockOff();
+const { defineTest } = require('jscodeshift/dist/testUtils');
+
+defineTest(__dirname, 'block-to-width-100', { quote: 'single' }, 'block-to-width-100', { parser: 'tsx' });
diff --git a/src/codemods/__tests__/colors-to-css-vars-test.ts b/src/codemods/__tests__/colors-to-css-vars-test.ts
new file mode 100644
index 000000000..43b702203
--- /dev/null
+++ b/src/codemods/__tests__/colors-to-css-vars-test.ts
@@ -0,0 +1,18 @@
+jest.autoMockOff();
+const { defineTest } = require('jscodeshift/dist/testUtils');
+
+const tests = [
+ 'color-in-JSX-multi-import',
+ 'color-in-JSX-single-import',
+ 'template-multi-quasis-even',
+ 'template-multi-quasis-odd',
+ 'template-single-quasis'
+];
+
+describe('colors-to-css-vars', () => {
+ tests.forEach(test =>
+ defineTest(__dirname, 'colors-to-css-vars', { quote: 'single' }, `colors-to-css-vars/${test}`, {
+ parser: 'tsx'
+ })
+ );
+});
diff --git a/src/codemods/block-to-width-100.ts b/src/codemods/block-to-width-100.ts
new file mode 100644
index 000000000..68d921cda
--- /dev/null
+++ b/src/codemods/block-to-width-100.ts
@@ -0,0 +1,59 @@
+import { API, FileInfo } from 'jscodeshift';
+import { Options } from 'recast';
+
+module.exports = (file: FileInfo, api: API, options: Options) => {
+ const j = api.jscodeshift;
+ const ast = j(file.source);
+ const printOptions = options ?? { quote: 'single' };
+
+ const localButtonNames = [];
+
+ const fullWidthProp = {
+ type: 'JSXAttribute',
+ name: 'width',
+ value: {
+ type: 'StringLiteral',
+ value: '100%'
+ }
+ };
+
+ ast.find(j.ImportDeclaration, decl => decl.source.value === '@freenow/wave').forEach(decl => {
+ j(decl)
+ .find(j.ImportSpecifier)
+ .forEach(spec => {
+ if (spec.node.imported.name === 'Button' || spec.node.imported.name === 'TextButton') {
+ localButtonNames.push(spec.node.local.name);
+ }
+ });
+ });
+
+ ast.find(j.JSXElement, {
+ openingElement: {
+ name: {
+ name: name => localButtonNames.includes(name)
+ }
+ }
+ }).forEach(el => {
+ j(el)
+ .find(j.JSXAttribute, {
+ name: name => name.name === 'block'
+ })
+ .forEach(attr => {
+ if (attr.value.value) {
+ j(attr)
+ .find(j.Literal)
+ .forEach(literal => {
+ if (literal.value.value === false) {
+ j(attr).remove();
+ } else {
+ j(attr).replaceWith(fullWidthProp);
+ }
+ });
+ } else {
+ j(attr).replaceWith(fullWidthProp);
+ }
+ });
+ });
+
+ return ast.toSource(printOptions);
+};
diff --git a/src/codemods/colors-to-css-vars.ts b/src/codemods/colors-to-css-vars.ts
new file mode 100644
index 000000000..a82c1ce2b
--- /dev/null
+++ b/src/codemods/colors-to-css-vars.ts
@@ -0,0 +1,159 @@
+import { API, FileInfo, Identifier, JSCodeshift, TemplateLiteral } from 'jscodeshift';
+import { Options } from 'recast';
+
+const ColorsToCssVariablesMap = {
+ WHITE: 'var(--wave-b-color-white)',
+ BLACK: 'var(--wave-b-color-black)',
+ AUTHENTIC_BLUE_1100: 'var(--wave-b-color-blue-primary-1100)',
+ AUTHENTIC_BLUE_900: 'var(--wave-b-color-blue-primary-900)',
+ AUTHENTIC_BLUE_550: 'var(--wave-b-color-blue-primary-550)',
+ AUTHENTIC_BLUE_350: 'var(--wave-b-color-blue-primary-350)',
+ AUTHENTIC_BLUE_200: 'var(--wave-b-color-blue-primary-200)',
+ AUTHENTIC_BLUE_50: 'var(--wave-b-color-blue-primary-50)',
+ FREEDOM_RED_1000: 'var(--wave-b-color-red-1000)',
+ FREEDOM_RED_900: 'var(--wave-b-color-red-900)',
+ ACTION_BLUE_1000: 'var(--wave-b-color-blue-secondary-1000)',
+ ACTION_BLUE_900: 'var(--wave-b-color-blue-secondary-900)',
+ ACTION_BLUE_350: 'var(--wave-b-color-blue-secondary-350)',
+ ACTION_BLUE_150: 'var(--wave-b-color-blue-secondary-150)',
+ ACTION_BLUE_100: 'var(--wave-b-color-blue-secondary-100)',
+ ACTION_BLUE_50: 'var(--wave-b-color-blue-secondary-50)',
+ BUMPY_MAGENTA_1000: 'var(--wave-b-color-magenta-1000)',
+ BUMPY_MAGENTA_900: 'var(--wave-b-color-magenta-900)',
+ BUMPY_MAGENTA_350: 'var(--wave-b-color-magenta-350)',
+ BUMPY_MAGENTA_50: 'var(--wave-b-color-magenta-50)',
+ POSITIVE_GREEN_1000: 'var(--wave-b-color-green-1000)',
+ POSITIVE_GREEN_900: 'var(--wave-b-color-green-900)',
+ POSITIVE_GREEN_350: 'var(--wave-b-color-green-350)',
+ POSITIVE_GREEN_50: 'var(--wave-b-color-green-50)',
+ ATTENTION_YELLOW_900: 'var(--wave-b-color-yellow-900)',
+ ATTENTION_YELLOW_350: 'var(--wave-b-color-yellow-350)',
+ ATTENTION_YELLOW_50: 'var(--wave-b-color-yellow-50)',
+ NEGATIVE_ORANGE_1000: 'var(--wave-b-color-orange-1000)',
+ NEGATIVE_ORANGE_900: 'var(--wave-b-color-orange-900)',
+ NEGATIVE_ORANGE_350: 'var(--wave-b-color-orange-350)',
+ NEGATIVE_ORANGE_50: 'var(--wave-b-color-orange-50)'
+};
+
+const replaceColorsForCssVarsInTemplateLiterals = (
+ j: JSCodeshift,
+ localColorNames: string[],
+ templateLiteral: TemplateLiteral
+) => {
+ const { quasis } = templateLiteral;
+ const { expressions } = templateLiteral;
+
+ const expressionsToRemoveIndexes: number[] = [];
+ const quasisToRemoveIndexes: number[] = [];
+
+ // Iterate over the quasis of the template string (the parts before the `${` and after the `}`)
+ // e.g. in the template string `color: ${Colors.x};` there are 2 quasis, `color: ` and `;`, the `Colors.x` is an expression
+ quasis.forEach((el, index) => {
+ const expressionAfterQuasis = expressions[index];
+
+ // Check if there are arrow functions inside the template string, since they can also have nested template string
+ if (expressionAfterQuasis && expressionAfterQuasis.type === 'ArrowFunctionExpression') {
+ const templateExpressions = j(expressionAfterQuasis).find(j.TemplateLiteral);
+
+ // For every template string in the arrow function recursively replace colors for css vars
+ templateExpressions.forEach(ex => replaceColorsForCssVarsInTemplateLiterals(j, localColorNames, ex.node));
+ }
+
+ // Check if the expression is a MemberExpression (regular object property access)
+ if (expressionAfterQuasis && expressionAfterQuasis.type === 'MemberExpression') {
+ const expressionObject = expressionAfterQuasis.object as Identifier;
+
+ // Identify if it's a usage of Colors
+ const isColorsExpression = localColorNames.includes(expressionObject.name);
+
+ if (isColorsExpression) {
+ // Find the color being used
+ const color = (expressionAfterQuasis.property as Identifier).name;
+ const cssVar: string = ColorsToCssVariablesMap[color];
+
+ if (!cssVar) return;
+
+ const nextQuasisValue = quasis[index + 1].value.raw;
+ // Append the mapped css var and the value of the next quasis to the end of the current quasis (where the color expression is)
+ el.value.raw = el.value.raw + cssVar + nextQuasisValue;
+
+ // Since the color is mapped to the css var we don't need the expression anymore, so we flag it for removal later
+ expressionsToRemoveIndexes.push(index);
+
+ // The number of quasis always has to match the number of expressions + 1, since we've flagged the expression for removal we need to
+ // flag the next quasis for removal as well, we've already appended it's value to the current one so we don't lose information
+ quasisToRemoveIndexes.push(index + 1);
+ }
+ }
+ });
+
+ // Check if there are any expression that have to be removed and remove them
+ expressionsToRemoveIndexes.forEach(indexToRemove => {
+ expressions.splice(indexToRemove, 1);
+ });
+
+ // Check if there are any quasis that have to be removed and remove them
+ quasisToRemoveIndexes.forEach(indexToRemove => {
+ quasis.splice(indexToRemove, 1);
+ });
+};
+
+export default (file: FileInfo, api: API, options: Options) => {
+ const j = api.jscodeshift;
+ const ast = j(file.source);
+ const printOptions = options ?? { quote: 'single' };
+
+ const localColorNames: string[] = [];
+
+ // Find @freenow/wave imports
+ const waveImports = ast.find(j.ImportDeclaration, {
+ source: {
+ value: '@freenow/wave'
+ }
+ });
+
+ const waveNamedImports = waveImports.find(j.ImportSpecifier);
+
+ // Find Colors named imports in @freenow/wave imports
+ const colorsImports = waveNamedImports.filter(path => path.node.imported.name === 'Colors');
+
+ // Get the local Colors import names
+ colorsImports.forEach(spec => {
+ if (spec.node.local?.name) localColorNames.push(spec.node.local.name);
+ });
+
+ // Iterate over template strings
+ ast.find(j.TaggedTemplateExpression).forEach(el => {
+ // Get template literals in template expression
+ const templateLiteral = el.node.quasi;
+ replaceColorsForCssVarsInTemplateLiterals(j, localColorNames, templateLiteral);
+ });
+
+ // Find all remaining Colors usage
+ ast.find(j.MemberExpression, {
+ object: {
+ name: (colorName: string) => localColorNames.includes(colorName)
+ }
+ }).forEach(ex => {
+ // Map the Color to a css var
+ const color = (ex.node.property as Identifier).name;
+ const cssVar = ColorsToCssVariablesMap[color];
+
+ if (!cssVar) return;
+
+ // Replace the Colors usage for a string literal (e.g. 'var(--wave-b-color-y)')
+ const cssVarStringNode = j.stringLiteral(ColorsToCssVariablesMap[color]);
+ ex.replace(cssVarStringNode);
+ });
+
+ // If it is the only named import from wave, remove the whole Wave import
+ if (waveImports.size() === 1 && waveNamedImports.size() === 1 && colorsImports.size() === 1) {
+ waveImports.remove();
+
+ // If there are other named imports from wave, remove only the Colors named import
+ } else if (waveNamedImports.size() > 1) {
+ colorsImports.remove();
+ }
+
+ return ast.toSource(printOptions);
+};
diff --git a/tsconfig.json b/tsconfig.json
index 1b12576c9..ddec86e8c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -20,5 +20,5 @@
]
},
"include": ["src/**/*"],
- "exclude": ["src/**/docs", "**/node_modules"]
+ "exclude": ["src/**/docs", "**/node_modules", "src/codemods/__*"]
}