diff --git a/modules/codemod/index.js b/modules/codemod/index.js index 09010d36e9..746654128f 100755 --- a/modules/codemod/index.js +++ b/modules/codemod/index.js @@ -81,6 +81,13 @@ const { describe: chalk.gray('The path to execute the transform in (recursively).'), }); }) + .command('v13 [path]', chalk.gray('Canvas Kit v12 > v13 upgrade transform'), yargs => { + yargs.positional('path', { + type: 'string', + default: '.', + describe: chalk.gray('The path to execute the transform in (recursively).'), + }); + }) .demandCommand(1, chalk.red.bold('You must provide a transform to apply.')) .strictCommands() .fail((msg, err, yargs) => { diff --git a/modules/codemod/lib/v13/index.ts b/modules/codemod/lib/v13/index.ts new file mode 100644 index 0000000000..e6ee147ee9 --- /dev/null +++ b/modules/codemod/lib/v13/index.ts @@ -0,0 +1,11 @@ +import {Transform} from 'jscodeshift'; + +const transform: Transform = (file, api, options) => { + // These will run in order. If your transform depends on others, place yours after dependent transforms + // const fixes = [ + // // add codemods here + // ]; + // return fixes.reduce((source, fix) => fix({...file, source}, api, options) as string, file.source); +}; + +export default transform; diff --git a/modules/codemod/lib/v13/utils/getImportRenameMap.ts b/modules/codemod/lib/v13/utils/getImportRenameMap.ts new file mode 100644 index 0000000000..d0c4a70039 --- /dev/null +++ b/modules/codemod/lib/v13/utils/getImportRenameMap.ts @@ -0,0 +1,63 @@ +import {Collection, JSCodeshift, CallExpression} from 'jscodeshift'; + +export function getImportRenameMap( + j: JSCodeshift, + root: Collection, + mainPackage = '@workday/canvas-kit-react', + packageName = '' +) { + let containsCanvasImports = false; + + // build import name remapping - in case someone renamed imports... + // i.e. `import { IconButton as StyledIconButton } ...` + const importMap: Record = {}; + const styledMap: Record = {}; + root.find(j.ImportDeclaration, node => { + // imports our module + const value = node.source.value; + if ( + typeof value === 'string' && + (value === mainPackage || value.startsWith(mainPackage) || value === packageName) + ) { + containsCanvasImports = true; + (node.specifiers || []).forEach(specifier => { + if (specifier.type === 'ImportSpecifier') { + if (!specifier.local || specifier.local.name === specifier.imported.name) { + importMap[specifier.imported.name] = specifier.imported.name; + } else { + importMap[specifier.imported.name] = specifier.local.name; + } + } + }); + } + return false; + }); + + root + .find(j.CallExpression, (node: CallExpression) => { + if ( + node.callee.type === 'Identifier' && + node.callee.name === 'styled' && + node.arguments[0].type === 'Identifier' + ) { + return true; + } + return false; + }) + .forEach(nodePath => { + if ( + (nodePath.parent.value.type === 'CallExpression' || + nodePath.parent.value.type === 'TaggedTemplateExpression') && + nodePath.parent.parent.value.type === 'VariableDeclarator' && + nodePath.parent.parent.value.id.type === 'Identifier' + ) { + const styledName = nodePath.parent.parent.value.id.name; + + if (nodePath.value.arguments[0].type === 'Identifier') { + styledMap[nodePath.value.arguments[0].name] = styledName; + } + } + }); + + return {containsCanvasImports, importMap, styledMap}; +} diff --git a/modules/docs/mdx/13.0-UPGRADE-GUIDE.mdx b/modules/docs/mdx/13.0-UPGRADE-GUIDE.mdx new file mode 100644 index 0000000000..5cfdd9e15f --- /dev/null +++ b/modules/docs/mdx/13.0-UPGRADE-GUIDE.mdx @@ -0,0 +1,132 @@ +import { Meta } from '@storybook/addon-docs'; +import { Table } from '@workday/canvas-kit-react/table'; +import { base, brand, system } from '@workday/canvas-tokens-web'; +import { StatusIndicator } from '@workday/canvas-kit-preview-react/status-indicator'; +import { cssVar } from '@workday/canvas-kit-styling'; +import { Box } from '@workday/canvas-kit-react/layout'; + + + +# Canvas Kit 13.0 Upgrade Guide + +This guide contains an overview of the changes in Canvas Kit v13. Please +[reach out](https://github.com/Workday/canvas-kit/issues/new?labels=bug&template=bug.md) if you have +any questions. + + +## Table of contents + +- [Codemod](#codemod) + - [Instructions](#instructions) +- [Troubleshooting](#troubleshooting) +- [Glossary](#glossary) + - [Main](#main) + - [Preview](#preview) + - [Labs](#labs) + +## Codemod + +We've provided a [codemod](https://github.com/Workday/canvas-kit/tree/master/modules/codemod) to +automatically update your code to work with most of the breaking changes in v13. **Breaking changes +handled by the codemod are marked with 🤖 in the Upgrade Guide.** + +A codemod is a script that makes programmatic transformations on your codebase by traversing the +[AST](https://www.codeshiftcommunity.com/docs/understanding-asts), identifying patterns, and making +prescribed changes. This greatly decreases opportunities for error and reduces the number of manual +updates, which allows you to focus on changes that need your attention. **We highly recommend you +use the codemod for these reasons.** + +If you're new to running codemods or if it's been a minute since you've used one, there are a few +things you'll want to keep in mind. + +- Our codemods are meant to be run sequentially. For example, if you're using v8 of Canvas Kit, + you'll need to run the v9 codemod before you run v10 and so on. +- The codemod will update your code to be compatible with the specified version, but it will **not** + remove outdated dependencies or upgrade dependencies to the latest version. You'll need to upgrade + dependencies on your own. + - We recommend upgrading dependencies before running the codemod. + - Always review your `package.json` files to make sure your dependency versions look correct. +- The codemod will not handle every breaking change in v13. You will likely need to make some manual + changes to be compatible. Use our Upgrade Guide as a checklist. +- Codemods are not bulletproof. + - Conduct a thorough PR and QA review of all changes to ensure no regressions were introduced. + - As a safety precaution, we recommend committing the changes from the codemod as a single + isolated commit (separate from other changes) so you can roll back more easily if necessary. + +We're here to help! Automatic changes to your codebase can feel scary. You can always reach out to +our team. We'd be very happy to walk you through the process to set you up for success. + +### Instructions + +The easiest way to run our codemod is to use `npx` in your terminal. + +```sh +npx @workday/canvas-kit-codemod v13 [path] +``` + +Be sure to provide specific directories that need to be updated via the `[path]` argument. This +decreases the amount of AST the codemod needs to traverse and reduces the chances of the script +having an error. For example, if your source code lives in `src/`, use `src/` as your `[path]`. Or, +if you have a monorepo with three packages using Canvas Kit, provide those specific packages as your +`[path]`. + +Alternatively, if you're unable to run the codemod successfully using `npx`, you can install the +codemod package as a dev dependency, run it with `yarn`, and then remove the package after you're +finished. + +```sh +yarn add @workday/canvas-kit-codemod --dev +yarn canvas-kit-codemod v13 [path] +yarn remove @workday/canvas-kit-codemod +``` + +> **Note**: The codemod only works on `.js`, `.jsx`, `.ts`, and `.tsx` files. You'll need to +> manually edit other file types (`.json`, `.mdx`, `.md`, etc.). You may need to run your linter +> after executing the codemod, as its resulting formatting (spacing, quotes, etc.) may not match +> your project conventions. + + +## Troubleshooting + +## Glossary + +### Main + +Our Main package of Canvas Kit tokens, components, and utilities at `@workday/canvas-kit-react` has +undergone a full design and a11y review and is approved for use in product. + +Breaking changes to code in Main will only occur during major version updates and will always be +communicated in advance and accompanied by migration strategies. + +--- + +### Preview + +Our Preview package of Canvas Kit tokens, components, and utilities at +`@workday/canvas-kit-preview-react` has undergone a full design and a11y review and is approved for +use in product, but may not be up to the high code standards upheld in the [Main](#main) package. +Preview is analagous to code in beta. + +Breaking changes are unlikely, but possible, and can be deployed to Preview at any time without +triggering a major version update, though such changes will be communicated in advance and +accompanied by migration strategies. + +Generally speaking, our goal is to eventually promote code from Preview to [Main](#main). +Occasionally, a component with the same name will exist in both [Main](#main) and Preview (for +example, see Segmented Control in [Preview](/components/buttons/segmented-control/) and +[Main](https://d2krrudi3mmzzw.cloudfront.net/v8/?path=/docs/components-buttons-segmented-control--basic)). +In these cases, Preview serves as a staging ground for an improved version of the component with a +different API. The component in [Main](#main) will eventually be replaced with the one in Preview. + +--- + +### Labs + +Our Labs package of Canvas Kit tokens, components, and utilities at `@workday/canvas-kit-labs-react` +has **not** undergone a full design and a11y review. Labs serves as an incubator space for new and +experimental code and is analagous to code in alpha. + +Breaking changes can be deployed to Labs at any time without triggering a major version update and +may not be subject to the same rigor in communcation and migration strategies reserved for breaking +changes in [Preview](#preview) and [Main](#main). +`import { opacity } from "@workday/canvas-tokens-web/dist/es6/system"` diff --git a/modules/docs/mdx/versionsTable.tsx b/modules/docs/mdx/versionsTable.tsx index a72d03d583..37424ae85d 100644 --- a/modules/docs/mdx/versionsTable.tsx +++ b/modules/docs/mdx/versionsTable.tsx @@ -4,40 +4,6 @@ import {StatusIndicator, StatusIndicatorVariant} from '@workday/canvas-kit-previ // @ts-ignore: Cannot find module error import {version} from '../../../lerna.json'; -// When we release a new version, add the support version before the first item. -const allVersions = [ - { - versionNumber: version, // This will always be the current major version - documentation: 'https://github.com/Workday/canvas-kit', - }, - { - versionNumber: 11, // This is support, update this when we release v13 - documentation: 'https://d2krrudi3mmzzw.cloudfront.net/v11/?path=/docs/welcome--page', - }, - { - versionNumber: 10, - documentation: 'https://d2krrudi3mmzzw.cloudfront.net/v10/?path=/docs/welcome--page', - }, - { - versionNumber: 9, - documentation: 'https://d2krrudi3mmzzw.cloudfront.net/v9/?path=/docs/welcome--page', - }, - { - versionNumber: 8, - documentation: 'https://d2krrudi3mmzzw.cloudfront.net/v8/?path=/docs/welcome--page', - }, - { - versionNumber: 7, - documentation: - 'https://d2krrudi3mmzzw.cloudfront.net/v7/?path=/story/welcome-getting-started--page', - }, - { - versionNumber: 6, - documentation: - 'https://d2krrudi3mmzzw.cloudfront.net/v7/?path=/story/welcome-getting-started--page', - }, -]; - const statusIndicators = { stable: { variant: 'blue', @@ -52,6 +18,12 @@ const statusIndicators = { label: 'No Longer Supported', }, }; + +type VersionType = { + versionNumber: number; + versionUrl: string; +}; + function getVersionStatusIndicator(versionNumber: number | string) { // version from lerna is a string, so we need to do modify into a number const currentMajorVersion = Number(version.split('.')[0]); @@ -69,6 +41,22 @@ function getVersionStatusIndicator(versionNumber: number | string) { } export const VersionTable = () => { + const [versions, setVersions] = React.useState([]); + const minVersion = 6; + const currentMajorVersion = Number(version?.split('.')[0]); + React.useEffect(() => { + let arr: VersionType[] = []; + for (let i = minVersion; i <= currentMajorVersion; i++) { + arr.push({ + versionNumber: i, + versionUrl: + i === currentMajorVersion + ? 'https://canvas.workday.com/' + : `https://canvas.workday.com/v${i}/`, + }); + } + setVersions(arr); + }, []); return ( @@ -79,24 +67,27 @@ export const VersionTable = () => { - {allVersions.map(item => { - const {label, variant} = getVersionStatusIndicator(item.versionNumber); - return ( - - v{item.versionNumber} - - - Documentation - - - - - {label} - - - - ); - })} + {versions + .slice() + .reverse() + .map(item => { + const {label, variant} = getVersionStatusIndicator(item.versionNumber); + return ( + + v{item.versionNumber} + + + Documentation + + + + + {label} + + + + ); + })}
);