@yahoo/uds 2.8.1 → 2.10.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/cli/bin/uds-darwin-arm64-baseline +0 -0
  2. package/cli/bin/uds-linux-arm64 +0 -0
  3. package/cli/bin/uds-linux-x64-baseline +0 -0
  4. package/cli/cli.ts +1 -1
  5. package/cli/codemods/addCommentAboveComponents.ts +4 -79
  6. package/cli/codemods/flattenButtonVariant.ts +143 -0
  7. package/cli/codemods/propsToClass.ts +7 -12
  8. package/cli/codemods/remapProps.ts +13 -12
  9. package/cli/codemods/replaceTwClassNameWithProp.ts +99 -0
  10. package/cli/codemods/utils/getGlobPattern.ts +11 -0
  11. package/cli/codemods/utils/getImportsFromPackage.ts +21 -0
  12. package/cli/codemods/utils/getJSXElements.ts +9 -0
  13. package/cli/codemods/utils/getProject.ts +17 -0
  14. package/cli/codemods/utils/hasJSXProperty.ts +14 -0
  15. package/cli/codemods/utils/index.ts +14 -0
  16. package/cli/codemods/utils/matchesJSXTagName.ts +14 -0
  17. package/cli/commands/codemod/flattenButtonVariant.ts +16 -0
  18. package/cli/commands/codemod/tailwindClassesToProps.ts +24 -0
  19. package/cli/tailwindcss.d.ts +2 -0
  20. package/cli/tsconfig.json +30 -8
  21. package/cli/utils/configWorker.ts +2 -2
  22. package/cli/utils/purgeCSS.ts +13 -3
  23. package/cli/utils/setupConfigWorker.ts +2 -1
  24. package/cli/utils/sortKeys.ts +5 -0
  25. package/dist/{Text-UCDorZDD.d.cts → Text-DC5H-ljU.d.cts} +29 -68
  26. package/dist/{Text-UCDorZDD.d.ts → Text-DC5H-ljU.d.ts} +29 -68
  27. package/dist/VStack-dsjTgotn.d.ts +145 -0
  28. package/dist/VStack-lZcVQtuR.d.cts +145 -0
  29. package/dist/analytics/server.js +1 -1
  30. package/dist/chunk-3R4CMTF2.js +2 -0
  31. package/dist/chunk-COT7GQ26.js +2 -0
  32. package/dist/chunk-DIZ6AEFQ.cjs +3 -0
  33. package/dist/chunk-GWUSJOIP.js +2 -0
  34. package/dist/chunk-GXWRHF26.cjs +1 -0
  35. package/dist/chunk-H35WDIEH.cjs +1 -0
  36. package/dist/chunk-IGRY2O2E.js +2 -0
  37. package/dist/chunk-IQXT3UML.cjs +2 -0
  38. package/dist/chunk-PLVCO2Q2.cjs +1 -0
  39. package/dist/chunk-RCTE4OK2.cjs +1 -0
  40. package/dist/chunk-ROCVTVD4.js +2 -0
  41. package/dist/chunk-SWTZ62RF.js +3 -0
  42. package/dist/chunk-TYCIDVTR.js +2 -0
  43. package/dist/chunk-UWAIMWW7.cjs +1 -0
  44. package/dist/client/index.cjs +2 -2
  45. package/dist/client/index.d.cts +917 -25
  46. package/dist/client/index.d.ts +917 -25
  47. package/dist/client/index.js +3 -3
  48. package/dist/experimental/client/index.cjs +2 -2
  49. package/dist/experimental/client/index.d.cts +14 -49
  50. package/dist/experimental/client/index.d.ts +14 -49
  51. package/dist/experimental/client/index.js +2 -2
  52. package/dist/experimental/index.cjs +2 -2
  53. package/dist/experimental/index.d.cts +4 -55
  54. package/dist/experimental/index.d.ts +4 -55
  55. package/dist/experimental/index.js +1 -1
  56. package/dist/fixtures.cjs +1545 -58
  57. package/dist/fixtures.d.cts +33 -14
  58. package/dist/fixtures.d.ts +33 -14
  59. package/dist/fixtures.js +1518 -52
  60. package/dist/flags.cjs +1 -1
  61. package/dist/flags.js +1 -1
  62. package/dist/index-B1ZHRmSN.d.ts +202 -0
  63. package/dist/index-By9VJ9yq.d.cts +202 -0
  64. package/dist/index.cjs +1 -1
  65. package/dist/index.d.cts +245 -128
  66. package/dist/index.d.ts +245 -128
  67. package/dist/index.js +1 -1
  68. package/dist/metafile-cjs.json +1 -1
  69. package/dist/metafile-esm.json +1 -1
  70. package/dist/tailwind/plugin.cjs +1 -2
  71. package/dist/tailwind/plugin.d.cts +14 -5
  72. package/dist/tailwind/plugin.d.ts +14 -5
  73. package/dist/tailwind/plugin.js +2 -2
  74. package/dist/tailwind/purger.cjs +2 -2
  75. package/dist/tailwind/purger.js +3 -3
  76. package/dist/tailwind/tsMorph.cjs +1 -1
  77. package/dist/tailwind/tsMorph.js +1 -1
  78. package/dist/tailwind/utils.cjs +1 -1
  79. package/dist/tailwind/utils.d.cts +80 -28
  80. package/dist/tailwind/utils.d.ts +80 -28
  81. package/dist/tailwind/utils.js +1 -1
  82. package/dist/tokens/automation/configs.cjs +1 -0
  83. package/dist/tokens/automation/configs.d.cts +110 -0
  84. package/dist/tokens/automation/configs.d.ts +110 -0
  85. package/dist/tokens/automation/configs.js +1 -0
  86. package/dist/tokens/automation/properties.cjs +1 -0
  87. package/dist/tokens/automation/properties.d.cts +7 -0
  88. package/dist/tokens/automation/properties.d.ts +7 -0
  89. package/dist/tokens/automation/properties.js +1 -0
  90. package/dist/tokens/index.cjs +1 -1
  91. package/dist/tokens/index.d.cts +9355 -15
  92. package/dist/tokens/index.d.ts +9355 -15
  93. package/dist/tokens/index.js +1 -1
  94. package/dist/tokens/parseTokens.cjs +1 -1
  95. package/dist/tokens/parseTokens.d.cts +7 -23
  96. package/dist/tokens/parseTokens.d.ts +7 -23
  97. package/dist/tokens/parseTokens.js +1 -1
  98. package/dist/types-oxQ-ciqn.d.cts +10237 -0
  99. package/dist/types-oxQ-ciqn.d.ts +10237 -0
  100. package/package.json +18 -4
  101. package/cli/PropsToClass.mock.tsx +0 -14
  102. package/dist/chunk-3G7IRLGN.js +0 -2
  103. package/dist/chunk-4ZZV37J4.js +0 -2
  104. package/dist/chunk-5WBROFT5.cjs +0 -1
  105. package/dist/chunk-5WTSHH5H.js +0 -1
  106. package/dist/chunk-6453EQCC.cjs +0 -1
  107. package/dist/chunk-D5OJRMIW.cjs +0 -2
  108. package/dist/chunk-EYFQOFYW.cjs +0 -1
  109. package/dist/chunk-FWF2C6TL.cjs +0 -1
  110. package/dist/chunk-GIJ2FHY5.cjs +0 -1
  111. package/dist/chunk-KTPYM4OO.js +0 -2
  112. package/dist/chunk-PE2P7J44.js +0 -2
  113. package/dist/chunk-PSLTRJPA.cjs +0 -2
  114. package/dist/chunk-RNQ6TDFL.cjs +0 -2
  115. package/dist/chunk-SUASN3GG.js +0 -2
  116. package/dist/chunk-TAPL6R6T.js +0 -3
  117. package/dist/chunk-TFSKZAZE.cjs +0 -1
  118. package/dist/chunk-VPR62GYQ.js +0 -2
  119. package/dist/chunk-X6F5UEQ5.js +0 -2
  120. package/dist/types-BjtmdiGC.d.cts +0 -989
  121. package/dist/types-BjtmdiGC.d.ts +0 -989
  122. /package/dist/{motionFeatures-PRT45UQH.js → motionFeatures-25DAPVNO.js} +0 -0
  123. /package/dist/{motionFeatures-HQUM526D.cjs → motionFeatures-II2BNXF5.cjs} +0 -0
Binary file
Binary file
Binary file
package/cli/cli.ts CHANGED
@@ -58,4 +58,4 @@ async function main() {
58
58
  await command.run(props);
59
59
  }
60
60
 
61
- main();
61
+ await main();
@@ -1,82 +1,7 @@
1
- import path from 'node:path';
1
+ import { IndentationText, Project } from 'ts-morph';
2
2
 
3
- import { IndentationText, Node, Project, SourceFile, SyntaxKind } from 'ts-morph';
4
-
5
- const getProject = () => {
6
- const workspaceDir = Bun.env.PWD;
7
- const srcDir = path.join(workspaceDir, 'tsconfig.json');
8
- return new Project({
9
- tsConfigFilePath: srcDir,
10
- manipulationSettings: { indentationText: IndentationText.TwoSpaces },
11
- });
12
- };
13
-
14
- const getGlobPattern = (selectedDirs?: string[]) => {
15
- let glob = './';
16
- if (selectedDirs && selectedDirs.length === 1) {
17
- glob += selectedDirs[0];
18
- } else if (selectedDirs) {
19
- glob += `{${selectedDirs.join(',')}}`;
20
- }
21
- glob += '/**/*.+(ts|tsx)';
22
-
23
- return glob;
24
- };
25
-
26
- /**
27
- * Gets the named imports being imported from `packageName` module.
28
- * @param sourceFile Source file to search for imports in.
29
- * @param packageName The package name to search in.
30
- */
31
- const getImportsFromPackage = (sourceFile: SourceFile, packageName: string) => {
32
- const importedComponents = new Set<string>();
33
-
34
- // Collect imports from '@yahoo/uds'
35
- sourceFile.getImportDeclarations().forEach((importDeclaration) => {
36
- if (importDeclaration.getModuleSpecifierValue() === packageName) {
37
- importDeclaration.getNamedImports().forEach((namedImport) => {
38
- importedComponents.add(namedImport.getName());
39
- });
40
- }
41
- });
42
-
43
- return importedComponents;
44
- };
45
-
46
- /** Returns true if the jsx element has a `propertyName` prop. */
47
- function hasJSXProperty(element: Node, propertyName: string) {
48
- if (!Node.isJsxElement(element) && !Node.isJsxSelfClosingElement(element)) {
49
- return false;
50
- }
51
-
52
- const openingElement = Node.isJsxElement(element) ? element.getOpeningElement() : element;
53
-
54
- return openingElement
55
- .getAttributes()
56
- .some((attr) => Node.isJsxAttribute(attr) && attr.getNameNode().getText() === propertyName);
57
- }
58
-
59
- /** Returns true if the name of the jsx element is `tagName`. */
60
- function matchesJSXTagName(element: Node, tagName: string) {
61
- if (!Node.isJsxElement(element) && !Node.isJsxSelfClosingElement(element)) {
62
- return false;
63
- }
64
-
65
- const tagNameNode = Node.isJsxElement(element)
66
- ? element.getOpeningElement().getTagNameNode()
67
- : element.getTagNameNode();
68
-
69
- return tagNameNode.getText() === tagName;
70
- }
71
-
72
- /** Gets the JSX elements in the source file. */
73
- function getJSXElements(sourceFile: SourceFile) {
74
- const jsxElements = [
75
- ...sourceFile.getDescendantsOfKind(SyntaxKind.JsxElement),
76
- ...sourceFile.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement),
77
- ];
78
- return jsxElements;
79
- }
3
+ import { getGlobPattern, getImportsFromPackage, getProject } from './utils';
4
+ import { getJSXElements, hasJSXProperty, matchesJSXTagName } from './utils';
80
5
 
81
6
  interface LineInfo {
82
7
  linePos: number;
@@ -138,7 +63,7 @@ export async function addCommentAboveComponents({
138
63
  });
139
64
 
140
65
  const updateSrc = srcLines.join('\n');
141
- console.log(updateSrc);
66
+ // console.log(updateSrc);
142
67
  sourceFile.replaceWithText(updateSrc);
143
68
  }
144
69
  });
@@ -0,0 +1,143 @@
1
+ import { Project, SyntaxKind } from 'ts-morph';
2
+
3
+ import { ButtonPalette, ButtonVariant, ButtonVariantFlat } from '~/tokens';
4
+
5
+ import { getGlobPattern, getImportsFromPackage, getProject } from './utils';
6
+
7
+ const buttonFlatValMap: Record<ButtonVariantFlat, ButtonVariantFlat> = {
8
+ primary: 'primary',
9
+ secondary: 'secondary',
10
+ tertiary: 'tertiary',
11
+ brand: 'brand',
12
+ alert: 'alert',
13
+ positive: 'positive',
14
+ warning: 'warning',
15
+ info: 'info',
16
+ 'brand-secondary': 'brand-secondary',
17
+ 'brand-tertiary': 'brand-tertiary',
18
+ 'alert-secondary': 'alert-secondary',
19
+ 'alert-tertiary': 'alert-tertiary',
20
+ 'positive-secondary': 'positive-secondary',
21
+ 'positive-tertiary': 'positive-tertiary',
22
+ 'warning-secondary': 'warning-secondary',
23
+ 'warning-tertiary': 'warning-tertiary',
24
+ 'info-secondary': 'info-secondary',
25
+ 'info-tertiary': 'info-tertiary',
26
+ };
27
+
28
+ // This is a hack to typecheck the keys of the object, ensure that all of the values are present
29
+ // NOTE: Importing fixtures still causes issues
30
+ const buttonVariantsFlat = Object.values(buttonFlatValMap);
31
+
32
+ function parseButtonVariantFlat({
33
+ palette = 'accent',
34
+ variant = 'primary',
35
+ }: {
36
+ palette?: ButtonPalette;
37
+ variant?: ButtonVariant;
38
+ }): ButtonVariantFlat {
39
+ if (palette === 'accent') {
40
+ return variant; // primary, secondary, tertiary
41
+ }
42
+
43
+ if (variant === 'primary') {
44
+ return palette; // brand, alert, positive, warning
45
+ }
46
+
47
+ return `${palette}-${variant}`; // brand-secondary, alert-tertiary, etc.
48
+ }
49
+
50
+ interface Options {
51
+ selectedDirs?: string[];
52
+ project?: Project;
53
+ }
54
+
55
+ /**
56
+ * Flatten palette and variant into a single variant prop for UDS Button and IconButton.
57
+ */
58
+ export async function flattenButtonVariant({ selectedDirs, project = getProject() }: Options) {
59
+ const glob = getGlobPattern(selectedDirs);
60
+ const sourceFiles = project.getSourceFiles(glob);
61
+
62
+ for (const sourceFile of sourceFiles) {
63
+ // Get UDS imports from '@yahoo/uds'
64
+ const importUdsComponents = getImportsFromPackage(sourceFile, '@yahoo/uds');
65
+
66
+ // Only process files that import Button or IconButton
67
+ if (!importUdsComponents.has('Button') && !importUdsComponents.has('IconButton')) {
68
+ continue;
69
+ }
70
+
71
+ // Process both JsxOpeningElement and JsxSelfClosingElement nodes.
72
+ const jsxElements = [
73
+ ...sourceFile.getDescendantsOfKind(SyntaxKind.JsxOpeningElement),
74
+ ...sourceFile.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement),
75
+ ].filter((el) => {
76
+ const tagName = el.getTagNameNode().getText();
77
+ return (tagName === 'Button' || tagName === 'IconButton') && importUdsComponents.has(tagName);
78
+ });
79
+
80
+ jsxElements.forEach((jsxEl) => {
81
+ // Get palette and variant attributes
82
+ const paletteAttr = jsxEl.getAttribute('palette');
83
+ const variantAttr = jsxEl.getAttribute('variant');
84
+
85
+ // Prepare to capture literal values.
86
+ let paletteLiteral: string | undefined;
87
+ let variantLiteral: string;
88
+
89
+ // Process palette attribute
90
+ if (paletteAttr) {
91
+ // @ts-expect-error - getInitializer() is not in the type definition
92
+ const initializer = paletteAttr.getInitializer();
93
+ if (initializer && initializer.getKind() === SyntaxKind.StringLiteral) {
94
+ paletteLiteral = initializer.getText().slice(1, -1);
95
+ }
96
+ }
97
+
98
+ // Process variant attribute
99
+ if (variantAttr) {
100
+ // @ts-expect-error - getInitializer() is not in the type definition
101
+ const initializer = variantAttr.getInitializer();
102
+ if (initializer && initializer.getKind() === SyntaxKind.StringLiteral) {
103
+ variantLiteral = initializer.getText().slice(1, -1);
104
+ } else {
105
+ variantLiteral = 'primary';
106
+ }
107
+ } else {
108
+ variantLiteral = 'primary';
109
+ }
110
+
111
+ // Remove the old palette and variant attributes.
112
+ if (paletteAttr) {
113
+ paletteAttr.remove();
114
+ }
115
+ if (variantAttr) {
116
+ variantAttr.remove();
117
+ }
118
+
119
+ if (!paletteLiteral && buttonVariantsFlat.includes(variantLiteral as ButtonVariantFlat)) {
120
+ // If the variant is already a valid flattened value, use it as is.
121
+ if (variantLiteral !== 'primary') {
122
+ // If its "primary", just remove all the props
123
+ jsxEl.addAttribute({
124
+ name: 'variant',
125
+ initializer: `"${variantLiteral}"`,
126
+ });
127
+ }
128
+ } else {
129
+ // Compute the flattened variant using the parsing function.
130
+ const flattened = parseButtonVariantFlat({
131
+ palette: paletteLiteral as ButtonPalette,
132
+ variant: variantLiteral as ButtonVariant,
133
+ });
134
+
135
+ jsxEl.addAttribute({
136
+ name: 'variant',
137
+ initializer: `"${flattened}"`,
138
+ });
139
+ }
140
+ });
141
+ }
142
+ await project.save();
143
+ }
@@ -11,6 +11,8 @@ import {
11
11
  SyntaxKind,
12
12
  } from 'ts-morph';
13
13
 
14
+ import { getGlobPattern } from './utils';
15
+
14
16
  const throwComplexExpressionWarning = ({
15
17
  attr,
16
18
  element,
@@ -70,6 +72,11 @@ const throwComplexExpressionWarning = ({
70
72
 
71
73
  export const getProject = () => {
72
74
  const workspaceDir = Bun.env.PWD;
75
+
76
+ if (!workspaceDir) {
77
+ throw new Error('Workspace directory not found.');
78
+ }
79
+
73
80
  const srcDir = path.join(workspaceDir, 'tsconfig.json');
74
81
  return new Project({
75
82
  tsConfigFilePath: srcDir,
@@ -77,18 +84,6 @@ export const getProject = () => {
77
84
  });
78
85
  };
79
86
 
80
- const getGlobPattern = (selectedDirs?: string[]) => {
81
- let glob = './';
82
- if (selectedDirs && selectedDirs.length === 1) {
83
- glob += selectedDirs[0];
84
- } else if (selectedDirs) {
85
- glob += `{${selectedDirs.join(',')}}`;
86
- }
87
- glob += '/**/*.+(ts|tsx)';
88
-
89
- return glob;
90
- };
91
-
92
87
  interface PropToClassMap {
93
88
  selectedDirs?: string[];
94
89
  project?: Project;
@@ -1,7 +1,7 @@
1
- import path from 'node:path';
2
-
3
1
  import { green, print, red } from 'bluebun';
4
- import { IndentationText, Project, SyntaxKind } from 'ts-morph';
2
+ import { SyntaxKind } from 'ts-morph';
3
+
4
+ import { getGlobPattern, getProject } from './utils';
5
5
 
6
6
  interface RemapPropsOptions {
7
7
  /** Properties to remap values for */
@@ -15,14 +15,8 @@ interface RemapPropsOptions {
15
15
  * For example, a UDS component with a prop of `spacing="6"` should be updated to `spacing="4"`.
16
16
  */
17
17
  export async function remapProps({ properties, oldToNewMap }: RemapPropsOptions) {
18
- const workspaceDir = Bun.env.PWD;
19
- const srcDir = path.join(workspaceDir, 'tsconfig.json');
20
- const project = new Project({
21
- tsConfigFilePath: srcDir,
22
- manipulationSettings: { indentationText: IndentationText.TwoSpaces },
23
- });
24
-
25
- const sourceFiles = project.getSourceFiles(`${workspaceDir}/**/*.{ts,tsx}`);
18
+ const project = getProject();
19
+ const sourceFiles = project.getSourceFiles(getGlobPattern());
26
20
 
27
21
  for (const sourceFile of sourceFiles) {
28
22
  const jsxOpeningElement = sourceFile.getDescendantsOfKind(SyntaxKind.JsxOpeningElement);
@@ -51,7 +45,14 @@ export async function remapProps({ properties, oldToNewMap }: RemapPropsOptions)
51
45
  if (newValue) {
52
46
  const oldLog = red(`${propName}=${oldValue}`);
53
47
  const newLog = green(`${propName}=${newValue}`);
54
- const relativePath = sourceFile.getFilePath().replace(Bun.env.PWD, '');
48
+
49
+ const workspaceDir = Bun.env.PWD;
50
+
51
+ if (!workspaceDir) {
52
+ throw new Error('Workspace directory not found.');
53
+ }
54
+
55
+ const relativePath = sourceFile.getFilePath().replace(workspaceDir, '');
55
56
  print(`${relativePath} ${oldLog} -> ${newLog}`);
56
57
  attribute.set({ name: propName, initializer: `"${newValue}"` });
57
58
  }
@@ -0,0 +1,99 @@
1
+ import { Node, Project, SyntaxKind } from 'ts-morph';
2
+
3
+ import { getGlobPattern, getImportsFromPackage, getProject } from './utils';
4
+
5
+ const getGlob = (selectedDirs?: string[]) => {
6
+ const glob = getGlobPattern(selectedDirs);
7
+ return [glob, '!**/*.d.ts', '!**/*/{vitest,tailwind,uds,site}.config.ts'];
8
+ };
9
+
10
+ interface Options {
11
+ /** Class names to replace with properties */
12
+ replacements: Record<string, Record<string, string>>;
13
+ /** Package to look in. @default '@yahoo/uds' */
14
+ packageName?: string;
15
+ selectedDirs?: string[];
16
+ project?: Project;
17
+ }
18
+
19
+ /**
20
+ * Replace tailwind classNames on UDS components with the equivalent UDS prop.
21
+ * Example: `w-full` -> `width="full"`.
22
+ */
23
+ export async function replaceTwClassNameWithProp({
24
+ selectedDirs,
25
+ packageName = '@yahoo/uds',
26
+ project = getProject(),
27
+ replacements,
28
+ }: Options) {
29
+ const glob = getGlob(selectedDirs);
30
+ const sourceFiles = project.getSourceFiles(glob);
31
+
32
+ for (const sourceFile of sourceFiles) {
33
+ const importUdsComponents = getImportsFromPackage(sourceFile, packageName);
34
+
35
+ // Find all nodes of JsxAttribute kind and filter for className attributes
36
+ const jsxAttributes = sourceFile
37
+ .getDescendantsOfKind(SyntaxKind.JsxAttribute)
38
+ .filter((node) => node.getNameNode().getText() === 'className');
39
+
40
+ // Process each className attribute
41
+ jsxAttributes.forEach((classNameAttr) => {
42
+ const initializer = classNameAttr.getInitializer();
43
+ if (!initializer) {
44
+ return;
45
+ }
46
+
47
+ // Navigate up to find JsxOpeningElement
48
+ const ancestors = classNameAttr.getAncestors();
49
+ const jsxOpeningElement = ancestors.find((node) => Node.isJsxOpeningElement(node));
50
+
51
+ if (!jsxOpeningElement) {
52
+ return;
53
+ }
54
+
55
+ // Only modify UDS components.
56
+ const componentName = jsxOpeningElement.getTagNameNode().getText();
57
+ const wasImportedFromUDS = importUdsComponents.has(componentName);
58
+ if (!wasImportedFromUDS) {
59
+ return;
60
+ }
61
+
62
+ // Get the className value
63
+ const classNameValue = initializer.getText().replace(/['"]/g, '');
64
+ const componentClasses = classNameValue.split(' ');
65
+
66
+ const replaceList = Object.keys(replacements);
67
+ const classesToSwitchToProps = new Set();
68
+ const remainingClasses = componentClasses
69
+ .filter((c) => {
70
+ if (replaceList.includes(c)) {
71
+ classesToSwitchToProps.add(c);
72
+ }
73
+ return !classesToSwitchToProps.has(c);
74
+ })
75
+ .join(' ');
76
+
77
+ // Remove the tw classes from the element which are listed in the replacements.
78
+ if (remainingClasses) {
79
+ classNameAttr.setInitializer(`"${remainingClasses}"`);
80
+ } else {
81
+ classNameAttr.remove();
82
+ }
83
+
84
+ // For each class that was replaced, add the corresponding prop.
85
+ for (const item of Object.entries(replacements)) {
86
+ const [prop, val] = Object.entries(item[1])[0];
87
+
88
+ if (classesToSwitchToProps.has(item[0])) {
89
+ jsxOpeningElement.insertAttribute(0, {
90
+ name: prop,
91
+ initializer: `"${val}"`,
92
+ });
93
+ }
94
+ }
95
+ });
96
+ }
97
+
98
+ await project.save();
99
+ }
@@ -0,0 +1,11 @@
1
+ export const getGlobPattern = (selectedDirs?: string[]) => {
2
+ let glob = './';
3
+ if (selectedDirs && selectedDirs.length === 1) {
4
+ glob += selectedDirs[0];
5
+ } else if (selectedDirs) {
6
+ glob += `{${selectedDirs.join(',')}}`;
7
+ }
8
+ glob += '/**/*.+(ts|tsx)';
9
+
10
+ return glob;
11
+ };
@@ -0,0 +1,21 @@
1
+ import { SourceFile } from 'ts-morph';
2
+
3
+ /**
4
+ * Gets the named imports being imported from `packageName` module.
5
+ * @param sourceFile Source file to search for imports in.
6
+ * @param packageName The package name to search in.
7
+ */
8
+ export const getImportsFromPackage = (sourceFile: SourceFile, packageName: string) => {
9
+ const importedComponents = new Set<string>();
10
+
11
+ // Collect imports from '@yahoo/uds'
12
+ sourceFile.getImportDeclarations().forEach((importDeclaration) => {
13
+ if (importDeclaration.getModuleSpecifierValue() === packageName) {
14
+ importDeclaration.getNamedImports().forEach((namedImport) => {
15
+ importedComponents.add(namedImport.getName());
16
+ });
17
+ }
18
+ });
19
+
20
+ return importedComponents;
21
+ };
@@ -0,0 +1,9 @@
1
+ import { SourceFile, SyntaxKind } from 'ts-morph';
2
+
3
+ /** Gets the JSX elements in the source file. */
4
+ export function getJSXElements(sourceFile: SourceFile) {
5
+ return [
6
+ ...sourceFile.getDescendantsOfKind(SyntaxKind.JsxElement),
7
+ ...sourceFile.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement),
8
+ ];
9
+ }
@@ -0,0 +1,17 @@
1
+ import path from 'node:path';
2
+
3
+ import { IndentationText, Project } from 'ts-morph';
4
+
5
+ export const getProject = () => {
6
+ const workspaceDir = Bun.env.PWD;
7
+
8
+ if (!workspaceDir) {
9
+ throw new Error('Workspace directory not found.');
10
+ }
11
+
12
+ const srcDir = path.join(workspaceDir, 'tsconfig.json');
13
+ return new Project({
14
+ tsConfigFilePath: srcDir,
15
+ manipulationSettings: { indentationText: IndentationText.TwoSpaces },
16
+ });
17
+ };
@@ -0,0 +1,14 @@
1
+ import { Node } from 'ts-morph';
2
+
3
+ /** Returns true if the jsx element has a `propertyName` prop. */
4
+ export function hasJSXProperty(element: Node, propertyName: string) {
5
+ if (!Node.isJsxElement(element) && !Node.isJsxSelfClosingElement(element)) {
6
+ return false;
7
+ }
8
+
9
+ const openingElement = Node.isJsxElement(element) ? element.getOpeningElement() : element;
10
+
11
+ return openingElement
12
+ .getAttributes()
13
+ .some((attr) => Node.isJsxAttribute(attr) && attr.getNameNode().getText() === propertyName);
14
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * ------------------- GENERATED | DO NOT MODIFY THIS SECTION ------------------
3
+ * This file uses eslint-plugin-codegen to automatically watch for changes in
4
+ * the `src/components` directory and updates this barrel file.
5
+ */
6
+ // codegen:start {preset: barrel, exclude: ['*.*.*']}
7
+ export * from './getGlobPattern';
8
+ export * from './getImportsFromPackage';
9
+ export * from './getJSXElements';
10
+ export * from './getProject';
11
+ export * from './hasJSXProperty';
12
+ export * from './matchesJSXTagName';
13
+ export * from './sizingPropToClassMap';
14
+ // codegen:end
@@ -0,0 +1,14 @@
1
+ import { Node } from 'ts-morph';
2
+
3
+ /** Returns true if the name of the jsx element is `tagName`. */
4
+ export function matchesJSXTagName(element: Node, tagName: string) {
5
+ if (!Node.isJsxElement(element) && !Node.isJsxSelfClosingElement(element)) {
6
+ return false;
7
+ }
8
+
9
+ const tagNameNode = Node.isJsxElement(element)
10
+ ? element.getOpeningElement().getTagNameNode()
11
+ : element.getTagNameNode();
12
+
13
+ return tagNameNode.getText() === tagName;
14
+ }
@@ -0,0 +1,16 @@
1
+ import { type Props, spinStart, spinStop } from 'bluebun';
2
+
3
+ import { flattenButtonVariant } from '../../codemods/flattenButtonVariant';
4
+
5
+ export default {
6
+ name: 'flattenButtonVariant',
7
+ description: `Flatten deprecated button props into single variant prop`,
8
+
9
+ run: async (props: Props & { selectedDirs?: string[] }) => {
10
+ spinStart('Running codemod...');
11
+
12
+ await flattenButtonVariant({ selectedDirs: props.selectedDirs });
13
+
14
+ spinStop('Codemod complete! Peek the diff and commit your changes!');
15
+ },
16
+ };
@@ -0,0 +1,24 @@
1
+ import { type Props, spinStart, spinStop } from 'bluebun';
2
+
3
+ import { replaceTwClassNameWithProp } from '../../codemods/replaceTwClassNameWithProp';
4
+
5
+ export default {
6
+ name: 'tailwindClassesToProps',
7
+ description: `Converts tailwind classes to UDS props (e.g. w-full => width="full").`,
8
+
9
+ run: async (props: Props & { selectedDirs?: string[] }) => {
10
+ spinStart('Running codemod...');
11
+ await replaceTwClassNameWithProp({
12
+ selectedDirs: props.selectedDirs,
13
+ replacements: {
14
+ 'w-fit': { width: 'fit' },
15
+ 'w-full': { width: 'full' },
16
+ 'w-screen': { width: 'screen' },
17
+ 'h-full': { height: 'full' },
18
+ 'h-screen': { height: 'screen' },
19
+ 'h-fit': { height: 'fit' },
20
+ },
21
+ });
22
+ spinStop('Codemod complete! Peek the diff and commit your changes!');
23
+ },
24
+ };
@@ -0,0 +1,2 @@
1
+ // The typecheck script is not able to find the `flattenColorPalette` function from TailwindCSS.
2
+ declare module 'tailwindcss/lib/util/flattenColorPalette';
package/cli/tsconfig.json CHANGED
@@ -1,8 +1,12 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/tsconfig",
3
3
  "display": "Default",
4
- "include": ["."],
5
- "exclude": ["node_modules"],
4
+ "include": [
5
+ "."
6
+ ],
7
+ "exclude": [
8
+ "node_modules"
9
+ ],
6
10
  "compilerOptions": {
7
11
  "composite": false,
8
12
  "declaration": true,
@@ -16,16 +20,34 @@
16
20
  "preserveWatchOutput": true,
17
21
  "skipLibCheck": true,
18
22
  "strict": true,
19
- "types": ["bun-types"],
23
+ "types": [
24
+ "bun-types"
25
+ ],
20
26
  "target": "esnext",
21
- "lib": ["ESNext"],
27
+ "lib": [
28
+ "ESNext"
29
+ ],
22
30
  "module": "esnext",
23
31
  "moduleResolution": "bundler",
24
32
  "paths": {
25
- "@yahoo/uds/scripts/*": ["../scripts/*"],
26
- "@yahoo/uds/*": ["../src/*"],
27
- "@yahoo/uds/tailwind/tsMorph": ["../scripts/utils/tsMorph.ts"],
28
- "root/*": ["../../*"]
33
+ "~/*": [
34
+ "../src/*"
35
+ ],
36
+ "@yahoo/uds/scripts/*": [
37
+ "../scripts/*"
38
+ ],
39
+ // "@yahoo/uds/tokens": [
40
+ // "../src/tokens/index.ts"
41
+ // ],
42
+ "@yahoo/uds/tailwind/purger": [
43
+ "../src/tailwind/purger/index.ts"
44
+ ],
45
+ "@yahoo/uds/tailwind/tsMorph": [
46
+ "../scripts/utils/tsMorph.ts"
47
+ ],
48
+ "root/*": [
49
+ "../../*"
50
+ ]
29
51
  }
30
52
  }
31
53
  }
@@ -8,7 +8,7 @@ import { eq, gte } from 'semver';
8
8
  import { ConfigWorkerThreadMessageEvent } from './types';
9
9
 
10
10
  const PRODUCTION_PREFIX = 'https://config.uds.build';
11
- const STAGING_PREFIX = 'https://staging.uds.build';
11
+ const STAGING_PREFIX = 'https://staging.config.uds.build';
12
12
  const LOCAL_PORT = process.env.PORT || 4001;
13
13
  const LOCAL_PREFIX = `http://localhost:${LOCAL_PORT}`;
14
14
 
@@ -16,7 +16,7 @@ let CONFIG_ENDPOINT = `${PRODUCTION_PREFIX}/api/config`;
16
16
 
17
17
  // Setup auth bypass for Vercel preview deployments (staging)
18
18
  const PROTECTION_BYPASS = process.env.VERCEL_PROTECTION_BYPASS ?? '';
19
- const FETCH_REQUEST_INIT: FetchRequestInit = {
19
+ const FETCH_REQUEST_INIT: BunFetchRequestInit = {
20
20
  headers: {
21
21
  'x-vercel-protection-bypass': PROTECTION_BYPASS,
22
22
  },