@sanity/ui-codemod 1.0.0-alpha.4 → 1.0.0-alpha.5
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.
- package/dist/_chunks-es/flex.mods.js +150 -1
- package/dist/_chunks-es/flex.mods.js.map +1 -1
- package/dist/transforms/latest/box/box.js +2 -148
- package/dist/transforms/latest/box/box.js.map +1 -1
- package/dist/transforms/latest/flex/flex.js +15 -7
- package/dist/transforms/latest/flex/flex.js.map +1 -1
- package/package.json +1 -1
- package/src/transforms/latest/box/box.test.ts +83 -143
- package/src/transforms/latest/flex/flex.test.ts +78 -1
- package/src/transforms/latest/flex/flex.ts +29 -9
- package/src/utils/testUtils.ts +45 -0
|
@@ -1,4 +1,151 @@
|
|
|
1
|
+
import { getComponentLocalNames, insertTodoWarning } from "./transformComponent.js";
|
|
2
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
3
|
+
import { resolve, dirname, join } from "node:path";
|
|
1
4
|
import { LAYOUT_MODS } from "./layout-mods.js";
|
|
5
|
+
const parseCache = /* @__PURE__ */ new Map();
|
|
6
|
+
function parseModule(j, filePath) {
|
|
7
|
+
const cached = parseCache.get(filePath);
|
|
8
|
+
if (cached)
|
|
9
|
+
return cached;
|
|
10
|
+
try {
|
|
11
|
+
const source = readFileSync(filePath, "utf8"), root = j(source);
|
|
12
|
+
return parseCache.set(filePath, root), root;
|
|
13
|
+
} catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const EXTENSIONS = [".tsx", ".ts", ".jsx", ".js"];
|
|
18
|
+
function resolveRelativeModulePath(fromFilePath, moduleSpecifier) {
|
|
19
|
+
if (!moduleSpecifier.startsWith("."))
|
|
20
|
+
return null;
|
|
21
|
+
const base = resolve(dirname(fromFilePath), moduleSpecifier);
|
|
22
|
+
for (const ext of EXTENSIONS) {
|
|
23
|
+
const filePath = `${base}${ext}`;
|
|
24
|
+
if (existsSync(filePath))
|
|
25
|
+
return filePath;
|
|
26
|
+
}
|
|
27
|
+
for (const ext of EXTENSIONS) {
|
|
28
|
+
const indexPath = join(base, `index${ext}`);
|
|
29
|
+
if (existsSync(indexPath))
|
|
30
|
+
return indexPath;
|
|
31
|
+
}
|
|
32
|
+
return existsSync(base) ? base : null;
|
|
33
|
+
}
|
|
34
|
+
function findVariableInit(j, root, name) {
|
|
35
|
+
let init = null;
|
|
36
|
+
return root.find(j.VariableDeclarator).forEach((path) => {
|
|
37
|
+
const { id } = path.node;
|
|
38
|
+
id.type === "Identifier" && id.name === name && path.node.init && (init = path.node.init);
|
|
39
|
+
}), init;
|
|
40
|
+
}
|
|
41
|
+
function getExportSpecifierName(exported) {
|
|
42
|
+
return exported.type === "Identifier" || exported.type === "JSXIdentifier" ? exported.name : null;
|
|
43
|
+
}
|
|
44
|
+
function getNamedExportInit(j, exportName, filePath, visited = /* @__PURE__ */ new Set()) {
|
|
45
|
+
if (visited.has(filePath))
|
|
46
|
+
return null;
|
|
47
|
+
visited.add(filePath);
|
|
48
|
+
const root = parseModule(j, filePath);
|
|
49
|
+
if (!root)
|
|
50
|
+
return null;
|
|
51
|
+
for (const path of root.find(j.ExportNamedDeclaration).paths()) {
|
|
52
|
+
const { declaration, specifiers, source } = path.node, reexportSource = typeof source?.value == "string" ? source.value : null;
|
|
53
|
+
if (declaration?.type === "VariableDeclaration") {
|
|
54
|
+
for (const declarator of declaration.declarations)
|
|
55
|
+
if (declarator.type === "VariableDeclarator" && declarator.id.type === "Identifier" && declarator.id.name === exportName && declarator.init)
|
|
56
|
+
return { init: declarator.init, modulePath: filePath };
|
|
57
|
+
}
|
|
58
|
+
for (const spec of specifiers ?? []) {
|
|
59
|
+
if (spec.type !== "ExportSpecifier")
|
|
60
|
+
continue;
|
|
61
|
+
const exported = getExportSpecifierName(spec.exported);
|
|
62
|
+
if (!exported || exported !== exportName)
|
|
63
|
+
continue;
|
|
64
|
+
const local = spec.local?.type === "Identifier" ? spec.local.name : exported;
|
|
65
|
+
if (reexportSource) {
|
|
66
|
+
const resolvedPath = resolveRelativeModulePath(filePath, reexportSource);
|
|
67
|
+
if (resolvedPath) {
|
|
68
|
+
const followed = getNamedExportInit(j, local, resolvedPath, visited);
|
|
69
|
+
if (followed)
|
|
70
|
+
return followed;
|
|
71
|
+
}
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const init = findVariableInit(j, root, local);
|
|
75
|
+
if (init)
|
|
76
|
+
return { init, modulePath: filePath };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
function getStyledComponentName(node) {
|
|
82
|
+
if (!node || typeof node != "object" || !("type" in node))
|
|
83
|
+
return null;
|
|
84
|
+
const current = node;
|
|
85
|
+
if (current.type === "TaggedTemplateExpression")
|
|
86
|
+
return getStyledComponentName(current.tag);
|
|
87
|
+
if (current.type === "CallExpression") {
|
|
88
|
+
const callee = current.callee;
|
|
89
|
+
if (callee && typeof callee == "object" && "type" in callee && callee.type === "Identifier" && "name" in callee && callee.name === "styled") {
|
|
90
|
+
const arg = current.arguments?.[0];
|
|
91
|
+
return arg && typeof arg == "object" && "type" in arg && arg.type === "Identifier" && "name" in arg ? arg.name : null;
|
|
92
|
+
}
|
|
93
|
+
return getStyledComponentName(callee);
|
|
94
|
+
}
|
|
95
|
+
return current.type === "MemberExpression" && current.object ? getStyledComponentName(current.object) : null;
|
|
96
|
+
}
|
|
97
|
+
function getSameFileStyledComponentAliases(j, root, localNames) {
|
|
98
|
+
const aliases = /* @__PURE__ */ new Set(), names = new Set(localNames);
|
|
99
|
+
return root.find(j.VariableDeclarator).forEach((path) => {
|
|
100
|
+
const { id, init } = path.node;
|
|
101
|
+
if (!init || id.type !== "Identifier")
|
|
102
|
+
return;
|
|
103
|
+
const baseComponent = getStyledComponentName(init);
|
|
104
|
+
baseComponent && names.has(baseComponent) && aliases.add(id.name);
|
|
105
|
+
}), aliases;
|
|
106
|
+
}
|
|
107
|
+
function getImportedStyledComponentAliases(j, root, componentName, filePath, options) {
|
|
108
|
+
const aliases = /* @__PURE__ */ new Set();
|
|
109
|
+
return filePath && root.find(j.ImportDeclaration).forEach((path) => {
|
|
110
|
+
const source = path.node.source.value;
|
|
111
|
+
if (typeof source != "string")
|
|
112
|
+
return;
|
|
113
|
+
const resolvedPath = resolveRelativeModulePath(filePath, source);
|
|
114
|
+
if (resolvedPath)
|
|
115
|
+
for (const spec of path.node.specifiers ?? []) {
|
|
116
|
+
if (spec.type !== "ImportSpecifier" || "importKind" in spec && spec.importKind === "type" || spec.imported.type !== "Identifier")
|
|
117
|
+
continue;
|
|
118
|
+
const exportName = spec.imported.name, localName = spec.local?.type === "Identifier" ? spec.local.name : exportName, namedExport = getNamedExportInit(j, exportName, resolvedPath);
|
|
119
|
+
if (!namedExport)
|
|
120
|
+
continue;
|
|
121
|
+
const sourceRoot = parseModule(j, namedExport.modulePath);
|
|
122
|
+
if (!sourceRoot)
|
|
123
|
+
continue;
|
|
124
|
+
const exportLocalNames = getComponentLocalNames(j, sourceRoot, componentName, options), baseComponent = getStyledComponentName(namedExport.init);
|
|
125
|
+
baseComponent && exportLocalNames.has(baseComponent) && aliases.add(localName);
|
|
126
|
+
}
|
|
127
|
+
}), aliases;
|
|
128
|
+
}
|
|
129
|
+
function getStyledComponentAliases(j, root, componentName, filePath, localNames, options) {
|
|
130
|
+
const sameFile = getSameFileStyledComponentAliases(j, root, localNames), imported = getImportedStyledComponentAliases(j, root, componentName, filePath, options);
|
|
131
|
+
return /* @__PURE__ */ new Set([...sameFile, ...imported]);
|
|
132
|
+
}
|
|
133
|
+
const DEFAULT_WARNING = "Please double check styled-component migration below";
|
|
134
|
+
function transformStyledComponents(j, root, aliases, filter, options = {}) {
|
|
135
|
+
const names = new Set(aliases), { callback, warning = DEFAULT_WARNING } = options;
|
|
136
|
+
let hasChanges = !1;
|
|
137
|
+
return root.find(j.JSXOpeningElement).forEach((path) => {
|
|
138
|
+
const name = path.node.name;
|
|
139
|
+
if (name.type !== "JSXIdentifier" || !names.has(name.name))
|
|
140
|
+
return;
|
|
141
|
+
const attrs = path.node.attributes ?? [];
|
|
142
|
+
if (!filter(attrs)) {
|
|
143
|
+
insertTodoWarning(j, path, warning) && (hasChanges = !0);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
callback?.(path) && (hasChanges = !0);
|
|
147
|
+
}), hasChanges;
|
|
148
|
+
}
|
|
2
149
|
const FLEX_MODS = {
|
|
3
150
|
...LAYOUT_MODS,
|
|
4
151
|
align: {
|
|
@@ -69,6 +216,8 @@ const FLEX_MODS = {
|
|
|
69
216
|
}
|
|
70
217
|
};
|
|
71
218
|
export {
|
|
72
|
-
FLEX_MODS
|
|
219
|
+
FLEX_MODS,
|
|
220
|
+
getStyledComponentAliases,
|
|
221
|
+
transformStyledComponents
|
|
73
222
|
};
|
|
74
223
|
//# sourceMappingURL=flex.mods.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flex.mods.js","sources":["../../src/transforms/latest/flex/flex.mods.ts"],"sourcesContent":["import {LAYOUT_MODS} from '../../../constants/latest/layout-mods'\nimport type {AttributeMods} from '../../../types/AttributeMods'\n\n/** @internal */\nexport const FLEX_MODS: AttributeMods = {\n ...LAYOUT_MODS,\n align: {\n type: 'rename-only',\n name: 'alignItems',\n },\n direction: {\n type: 'rename-only',\n name: 'flexDirection',\n },\n gridAutoColumns: {\n type: 'style-only',\n style: 'gridAutoColumns',\n },\n gridAutoFlow: {\n type: 'style-only',\n style: 'gridAutoFlow',\n },\n gridAutoRows: {\n type: 'style-only',\n style: 'gridAutoRows',\n },\n gridTemplateColumns: {\n type: 'style-mapped',\n style: 'gridTemplateColumns',\n mapping: {\n 0: '0px',\n 1: 'repeat(1, 1fr)',\n 2: 'repeat(2, 1fr)',\n 3: 'repeat(3, 1fr)',\n 4: 'repeat(4, 1fr)',\n 5: 'repeat(5, 1fr)',\n 6: 'repeat(6, 1fr)',\n 7: 'repeat(7, 1fr)',\n 8: 'repeat(8, 1fr)',\n 9: 'repeat(9, 1fr)',\n 10: 'repeat(10, 1fr)',\n 11: 'repeat(11, 1fr)',\n 12: 'repeat(12, 1fr)',\n },\n },\n gridTemplateRows: {\n type: 'style-mapped',\n style: 'gridTemplateRows',\n mapping: {\n 0: '0px',\n 1: 'repeat(1, 1fr)',\n 2: 'repeat(2, 1fr)',\n 3: 'repeat(3, 1fr)',\n 4: 'repeat(4, 1fr)',\n 5: 'repeat(5, 1fr)',\n 6: 'repeat(6, 1fr)',\n 7: 'repeat(7, 1fr)',\n 8: 'repeat(8, 1fr)',\n 9: 'repeat(9, 1fr)',\n 10: 'repeat(10, 1fr)',\n 11: 'repeat(11, 1fr)',\n 12: 'repeat(12, 1fr)',\n },\n },\n wrap: {\n type: 'rename-only',\n name: 'flexWrap',\n },\n justify: {\n type: 'rename-only',\n name: 'justifyContent',\n },\n}\n"],"names":[],"mappings":";AAIO,MAAM,YAA2B;AAAA,EACtC,GAAG;AAAA,EACH,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,EAAA;AAAA,EAER,WAAW;AAAA,IACT,MAAM;AAAA,IACN,MAAM;AAAA,EAAA;AAAA,EAER,iBAAiB;AAAA,IACf,MAAM;AAAA,IACN,OAAO;AAAA,EAAA;AAAA,EAET,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,OAAO;AAAA,EAAA;AAAA,EAET,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,OAAO;AAAA,EAAA;AAAA,EAET,qBAAqB;AAAA,IACnB,MAAM;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,MACP,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IAAA;AAAA,EACN;AAAA,EAEF,kBAAkB;AAAA,IAChB,MAAM;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,MACP,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IAAA;AAAA,EACN;AAAA,EAEF,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,EAAA;AAAA,EAER,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,EAAA;AAEV;"}
|
|
1
|
+
{"version":3,"file":"flex.mods.js","sources":["../../src/utils/parseModule.ts","../../src/utils/resolveRelativeModulePath.ts","../../src/utils/getNamedExportInit.ts","../../src/utils/getStyledComponentName.ts","../../src/utils/getStyledComponentAliases.ts","../../src/utils/transformStyledComponents.ts","../../src/transforms/latest/flex/flex.mods.ts"],"sourcesContent":["import {readFileSync} from 'node:fs'\n\nimport type {API, Collection} from 'jscodeshift'\n\nconst parseCache = new Map<string, Collection>()\n\nexport function parseModule(j: API['jscodeshift'], filePath: string): Collection | null {\n const cached = parseCache.get(filePath)\n\n if (cached) {\n return cached\n }\n\n try {\n const source = readFileSync(filePath, 'utf8')\n const root = j(source)\n\n parseCache.set(filePath, root)\n\n return root\n } catch {\n return null\n }\n}\n\n/** @internal */\nexport function clearModuleParseCache(): void {\n parseCache.clear()\n}\n","import {existsSync} from 'node:fs'\nimport {dirname, join, resolve} from 'node:path'\n\nconst EXTENSIONS = ['.tsx', '.ts', '.jsx', '.js'] as const\n\nexport function resolveRelativeModulePath(\n fromFilePath: string,\n moduleSpecifier: string,\n): string | null {\n if (!moduleSpecifier.startsWith('.')) {\n return null\n }\n\n const base = resolve(dirname(fromFilePath), moduleSpecifier)\n\n for (const ext of EXTENSIONS) {\n const filePath = `${base}${ext}`\n\n if (existsSync(filePath)) {\n return filePath\n }\n }\n\n for (const ext of EXTENSIONS) {\n const indexPath = join(base, `index${ext}`)\n\n if (existsSync(indexPath)) {\n return indexPath\n }\n }\n\n if (existsSync(base)) {\n return base\n }\n\n return null\n}\n","import type {API, Expression, ExportSpecifier} from 'jscodeshift'\n\nimport {parseModule} from './parseModule'\nimport {resolveRelativeModulePath} from './resolveRelativeModulePath'\n\nexport type NamedExportInit = {\n init: Expression\n modulePath: string\n}\n\nfunction findVariableInit(\n j: API['jscodeshift'],\n root: ReturnType<API['jscodeshift']>,\n name: string,\n): Expression | null {\n let init: Expression | null = null\n\n root.find(j.VariableDeclarator).forEach((path) => {\n const {id} = path.node\n\n if (id.type === 'Identifier' && id.name === name && path.node.init) {\n init = path.node.init\n }\n })\n\n return init\n}\n\nfunction getExportSpecifierName(exported: ExportSpecifier['exported']): string | null {\n if (exported.type === 'Identifier' || exported.type === 'JSXIdentifier') {\n return exported.name\n }\n\n return null\n}\n\nexport function getNamedExportInit(\n j: API['jscodeshift'],\n exportName: string,\n filePath: string,\n visited: Set<string> = new Set(),\n): NamedExportInit | null {\n if (visited.has(filePath)) {\n return null\n }\n\n visited.add(filePath)\n\n const root = parseModule(j, filePath)\n\n if (!root) {\n return null\n }\n\n for (const path of root.find(j.ExportNamedDeclaration).paths()) {\n const {declaration, specifiers, source} = path.node\n const reexportSource = typeof source?.value === 'string' ? source.value : null\n\n if (declaration?.type === 'VariableDeclaration') {\n for (const declarator of declaration.declarations) {\n if (declarator.type !== 'VariableDeclarator') {\n continue\n }\n\n if (\n declarator.id.type === 'Identifier' &&\n declarator.id.name === exportName &&\n declarator.init\n ) {\n return {init: declarator.init, modulePath: filePath}\n }\n }\n }\n\n for (const spec of specifiers ?? []) {\n if (spec.type !== 'ExportSpecifier') {\n continue\n }\n\n const exported = getExportSpecifierName(spec.exported)\n\n if (!exported || exported !== exportName) {\n continue\n }\n\n const local = spec.local?.type === 'Identifier' ? spec.local.name : exported\n\n if (reexportSource) {\n const resolvedPath = resolveRelativeModulePath(filePath, reexportSource)\n\n if (resolvedPath) {\n const followed = getNamedExportInit(j, local, resolvedPath, visited)\n\n if (followed) {\n return followed\n }\n }\n\n continue\n }\n\n const init = findVariableInit(j, root, local)\n\n if (init) {\n return {init, modulePath: filePath}\n }\n }\n }\n\n return null\n}\n","export function getStyledComponentName(node: unknown): string | null {\n if (!node || typeof node !== 'object' || !('type' in node)) {\n return null\n }\n\n const current = node as {\n type: string\n callee?: unknown\n tag?: unknown\n object?: unknown\n arguments?: unknown[]\n }\n\n if (current.type === 'TaggedTemplateExpression') {\n return getStyledComponentName(current.tag)\n }\n\n if (current.type === 'CallExpression') {\n const callee = current.callee\n\n if (\n callee &&\n typeof callee === 'object' &&\n 'type' in callee &&\n callee.type === 'Identifier' &&\n 'name' in callee &&\n callee.name === 'styled'\n ) {\n const arg = current.arguments?.[0]\n\n if (\n arg &&\n typeof arg === 'object' &&\n 'type' in arg &&\n arg.type === 'Identifier' &&\n 'name' in arg\n ) {\n return arg.name as string\n }\n\n return null\n }\n\n return getStyledComponentName(callee)\n }\n\n if (current.type === 'MemberExpression' && current.object) {\n return getStyledComponentName(current.object)\n }\n\n return null\n}\n","import type {API, Collection} from 'jscodeshift'\n\nimport type {BaseOptions} from '../types/BaseOptions'\nimport {getComponentLocalNames} from './getComponentLocalNames'\nimport {getNamedExportInit} from './getNamedExportInit'\nimport {getStyledComponentName} from './getStyledComponentName'\nimport {parseModule} from './parseModule'\nimport {resolveRelativeModulePath} from './resolveRelativeModulePath'\n\nexport function getSameFileStyledComponentAliases(\n j: API['jscodeshift'],\n root: Collection,\n localNames: Iterable<string>,\n): Set<string> {\n const aliases = new Set<string>()\n const names = new Set(localNames)\n\n root.find(j.VariableDeclarator).forEach((path) => {\n const {id, init} = path.node\n\n if (!init || id.type !== 'Identifier') {\n return\n }\n\n const baseComponent = getStyledComponentName(init)\n\n if (baseComponent && names.has(baseComponent)) {\n aliases.add(id.name)\n }\n })\n\n return aliases\n}\n\nexport function getImportedStyledComponentAliases(\n j: API['jscodeshift'],\n root: Collection,\n componentName: string,\n filePath: string | undefined,\n options?: BaseOptions,\n): Set<string> {\n const aliases = new Set<string>()\n\n if (!filePath) {\n return aliases\n }\n\n root.find(j.ImportDeclaration).forEach((path) => {\n const source = path.node.source.value\n\n if (typeof source !== 'string') {\n return\n }\n\n const resolvedPath = resolveRelativeModulePath(filePath, source)\n\n if (!resolvedPath) {\n return\n }\n\n for (const spec of path.node.specifiers ?? []) {\n if (spec.type !== 'ImportSpecifier') {\n continue\n }\n\n if ('importKind' in spec && spec.importKind === 'type') {\n continue\n }\n\n if (spec.imported.type !== 'Identifier') {\n continue\n }\n\n const exportName = spec.imported.name\n const localName = spec.local?.type === 'Identifier' ? spec.local.name : exportName\n const namedExport = getNamedExportInit(j, exportName, resolvedPath)\n\n if (!namedExport) {\n continue\n }\n\n const sourceRoot = parseModule(j, namedExport.modulePath)\n\n if (!sourceRoot) {\n continue\n }\n\n const exportLocalNames = getComponentLocalNames(j, sourceRoot, componentName, options)\n const baseComponent = getStyledComponentName(namedExport.init)\n\n if (baseComponent && exportLocalNames.has(baseComponent)) {\n aliases.add(localName)\n }\n }\n })\n\n return aliases\n}\n\nexport function getStyledComponentAliases(\n j: API['jscodeshift'],\n root: Collection,\n componentName: string,\n filePath: string | undefined,\n localNames: Set<string>,\n options?: BaseOptions,\n): Set<string> {\n const sameFile = getSameFileStyledComponentAliases(j, root, localNames)\n const imported = getImportedStyledComponentAliases(j, root, componentName, filePath, options)\n\n return new Set([...sameFile, ...imported])\n}\n","import type {API, ASTPath, JSXAttribute, JSXOpeningElement, JSXSpreadAttribute} from 'jscodeshift'\n\nimport {insertTodoWarning} from './insertTodoWarning'\n\nconst DEFAULT_WARNING = 'Please double check styled-component migration below'\n\n/**\n * Runs callback on JSX styled-component if `filter` passes. Otherwise, adds\n * a TODO on the component JSX instance when manual review is needed.\n * Returns whether the AST was updated.\n */\nexport function transformStyledComponents(\n j: API['jscodeshift'],\n root: ReturnType<API['jscodeshift']>,\n aliases: Iterable<string>,\n filter: (attrs: (JSXAttribute | JSXSpreadAttribute)[]) => boolean,\n options: {\n callback?: (path: ASTPath<JSXOpeningElement>) => boolean | void\n warning?: string\n } = {},\n): boolean {\n const names = new Set(aliases)\n const {callback, warning = DEFAULT_WARNING} = options\n let hasChanges = false\n\n root.find(j.JSXOpeningElement).forEach((path) => {\n const name = path.node.name\n\n if (name.type !== 'JSXIdentifier' || !names.has(name.name)) {\n return\n }\n\n const attrs = path.node.attributes ?? []\n\n if (!filter(attrs)) {\n if (insertTodoWarning(j, path, warning)) {\n hasChanges = true\n }\n\n return\n }\n\n if (callback?.(path)) {\n hasChanges = true\n }\n })\n\n return hasChanges\n}\n","import {LAYOUT_MODS} from '../../../constants/latest/layout-mods'\nimport type {AttributeMods} from '../../../types/AttributeMods'\n\n/** @internal */\nexport const FLEX_MODS: AttributeMods = {\n ...LAYOUT_MODS,\n align: {\n type: 'rename-only',\n name: 'alignItems',\n },\n direction: {\n type: 'rename-only',\n name: 'flexDirection',\n },\n gridAutoColumns: {\n type: 'style-only',\n style: 'gridAutoColumns',\n },\n gridAutoFlow: {\n type: 'style-only',\n style: 'gridAutoFlow',\n },\n gridAutoRows: {\n type: 'style-only',\n style: 'gridAutoRows',\n },\n gridTemplateColumns: {\n type: 'style-mapped',\n style: 'gridTemplateColumns',\n mapping: {\n 0: '0px',\n 1: 'repeat(1, 1fr)',\n 2: 'repeat(2, 1fr)',\n 3: 'repeat(3, 1fr)',\n 4: 'repeat(4, 1fr)',\n 5: 'repeat(5, 1fr)',\n 6: 'repeat(6, 1fr)',\n 7: 'repeat(7, 1fr)',\n 8: 'repeat(8, 1fr)',\n 9: 'repeat(9, 1fr)',\n 10: 'repeat(10, 1fr)',\n 11: 'repeat(11, 1fr)',\n 12: 'repeat(12, 1fr)',\n },\n },\n gridTemplateRows: {\n type: 'style-mapped',\n style: 'gridTemplateRows',\n mapping: {\n 0: '0px',\n 1: 'repeat(1, 1fr)',\n 2: 'repeat(2, 1fr)',\n 3: 'repeat(3, 1fr)',\n 4: 'repeat(4, 1fr)',\n 5: 'repeat(5, 1fr)',\n 6: 'repeat(6, 1fr)',\n 7: 'repeat(7, 1fr)',\n 8: 'repeat(8, 1fr)',\n 9: 'repeat(9, 1fr)',\n 10: 'repeat(10, 1fr)',\n 11: 'repeat(11, 1fr)',\n 12: 'repeat(12, 1fr)',\n },\n },\n wrap: {\n type: 'rename-only',\n name: 'flexWrap',\n },\n justify: {\n type: 'rename-only',\n name: 'justifyContent',\n },\n}\n"],"names":[],"mappings":";;;;AAIA,MAAM,iCAAiB,IAAA;AAEhB,SAAS,YAAY,GAAuB,UAAqC;AACtF,QAAM,SAAS,WAAW,IAAI,QAAQ;AAEtC,MAAI;AACF,WAAO;AAGT,MAAI;AACF,UAAM,SAAS,aAAa,UAAU,MAAM,GACtC,OAAO,EAAE,MAAM;AAErB,WAAA,WAAW,IAAI,UAAU,IAAI,GAEtB;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;ACpBA,MAAM,aAAa,CAAC,QAAQ,OAAO,QAAQ,KAAK;AAEzC,SAAS,0BACd,cACA,iBACe;AACf,MAAI,CAAC,gBAAgB,WAAW,GAAG;AACjC,WAAO;AAGT,QAAM,OAAO,QAAQ,QAAQ,YAAY,GAAG,eAAe;AAE3D,aAAW,OAAO,YAAY;AAC5B,UAAM,WAAW,GAAG,IAAI,GAAG,GAAG;AAE9B,QAAI,WAAW,QAAQ;AACrB,aAAO;AAAA,EAEX;AAEA,aAAW,OAAO,YAAY;AAC5B,UAAM,YAAY,KAAK,MAAM,QAAQ,GAAG,EAAE;AAE1C,QAAI,WAAW,SAAS;AACtB,aAAO;AAAA,EAEX;AAEA,SAAI,WAAW,IAAI,IACV,OAGF;AACT;AC1BA,SAAS,iBACP,GACA,MACA,MACmB;AACnB,MAAI,OAA0B;AAE9B,SAAA,KAAK,KAAK,EAAE,kBAAkB,EAAE,QAAQ,CAAC,SAAS;AAChD,UAAM,EAAC,OAAM,KAAK;AAEd,OAAG,SAAS,gBAAgB,GAAG,SAAS,QAAQ,KAAK,KAAK,SAC5D,OAAO,KAAK,KAAK;AAAA,EAErB,CAAC,GAEM;AACT;AAEA,SAAS,uBAAuB,UAAsD;AACpF,SAAI,SAAS,SAAS,gBAAgB,SAAS,SAAS,kBAC/C,SAAS,OAGX;AACT;AAEO,SAAS,mBACd,GACA,YACA,UACA,UAAuB,oBAAI,OACH;AACxB,MAAI,QAAQ,IAAI,QAAQ;AACtB,WAAO;AAGT,UAAQ,IAAI,QAAQ;AAEpB,QAAM,OAAO,YAAY,GAAG,QAAQ;AAEpC,MAAI,CAAC;AACH,WAAO;AAGT,aAAW,QAAQ,KAAK,KAAK,EAAE,sBAAsB,EAAE,SAAS;AAC9D,UAAM,EAAC,aAAa,YAAY,OAAA,IAAU,KAAK,MACzC,iBAAiB,OAAO,QAAQ,SAAU,WAAW,OAAO,QAAQ;AAE1E,QAAI,aAAa,SAAS;AACxB,iBAAW,cAAc,YAAY;AACnC,YAAI,WAAW,SAAS,wBAKtB,WAAW,GAAG,SAAS,gBACvB,WAAW,GAAG,SAAS,cACvB,WAAW;AAEX,iBAAO,EAAC,MAAM,WAAW,MAAM,YAAY,SAAA;AAAA;AAKjD,eAAW,QAAQ,cAAc,IAAI;AACnC,UAAI,KAAK,SAAS;AAChB;AAGF,YAAM,WAAW,uBAAuB,KAAK,QAAQ;AAErD,UAAI,CAAC,YAAY,aAAa;AAC5B;AAGF,YAAM,QAAQ,KAAK,OAAO,SAAS,eAAe,KAAK,MAAM,OAAO;AAEpE,UAAI,gBAAgB;AAClB,cAAM,eAAe,0BAA0B,UAAU,cAAc;AAEvE,YAAI,cAAc;AAChB,gBAAM,WAAW,mBAAmB,GAAG,OAAO,cAAc,OAAO;AAEnE,cAAI;AACF,mBAAO;AAAA,QAEX;AAEA;AAAA,MACF;AAEA,YAAM,OAAO,iBAAiB,GAAG,MAAM,KAAK;AAE5C,UAAI;AACF,eAAO,EAAC,MAAM,YAAY,SAAA;AAAA,IAE9B;AAAA,EACF;AAEA,SAAO;AACT;AC9GO,SAAS,uBAAuB,MAA8B;AACnE,MAAI,CAAC,QAAQ,OAAO,QAAS,YAAY,EAAE,UAAU;AACnD,WAAO;AAGT,QAAM,UAAU;AAQhB,MAAI,QAAQ,SAAS;AACnB,WAAO,uBAAuB,QAAQ,GAAG;AAG3C,MAAI,QAAQ,SAAS,kBAAkB;AACrC,UAAM,SAAS,QAAQ;AAEvB,QACE,UACA,OAAO,UAAW,YAClB,UAAU,UACV,OAAO,SAAS,gBAChB,UAAU,UACV,OAAO,SAAS,UAChB;AACA,YAAM,MAAM,QAAQ,YAAY,CAAC;AAEjC,aACE,OACA,OAAO,OAAQ,YACf,UAAU,OACV,IAAI,SAAS,gBACb,UAAU,MAEH,IAAI,OAGN;AAAA,IACT;AAEA,WAAO,uBAAuB,MAAM;AAAA,EACtC;AAEA,SAAI,QAAQ,SAAS,sBAAsB,QAAQ,SAC1C,uBAAuB,QAAQ,MAAM,IAGvC;AACT;AC1CO,SAAS,kCACd,GACA,MACA,YACa;AACb,QAAM,UAAU,oBAAI,IAAA,GACd,QAAQ,IAAI,IAAI,UAAU;AAEhC,SAAA,KAAK,KAAK,EAAE,kBAAkB,EAAE,QAAQ,CAAC,SAAS;AAChD,UAAM,EAAC,IAAI,KAAA,IAAQ,KAAK;AAExB,QAAI,CAAC,QAAQ,GAAG,SAAS;AACvB;AAGF,UAAM,gBAAgB,uBAAuB,IAAI;AAE7C,qBAAiB,MAAM,IAAI,aAAa,KAC1C,QAAQ,IAAI,GAAG,IAAI;AAAA,EAEvB,CAAC,GAEM;AACT;AAEO,SAAS,kCACd,GACA,MACA,eACA,UACA,SACa;AACb,QAAM,8BAAc,IAAA;AAEpB,SAAK,YAIL,KAAK,KAAK,EAAE,iBAAiB,EAAE,QAAQ,CAAC,SAAS;AAC/C,UAAM,SAAS,KAAK,KAAK,OAAO;AAEhC,QAAI,OAAO,UAAW;AACpB;AAGF,UAAM,eAAe,0BAA0B,UAAU,MAAM;AAE/D,QAAK;AAIL,iBAAW,QAAQ,KAAK,KAAK,cAAc,CAAA,GAAI;AAS7C,YARI,KAAK,SAAS,qBAId,gBAAgB,QAAQ,KAAK,eAAe,UAI5C,KAAK,SAAS,SAAS;AACzB;AAGF,cAAM,aAAa,KAAK,SAAS,MAC3B,YAAY,KAAK,OAAO,SAAS,eAAe,KAAK,MAAM,OAAO,YAClE,cAAc,mBAAmB,GAAG,YAAY,YAAY;AAElE,YAAI,CAAC;AACH;AAGF,cAAM,aAAa,YAAY,GAAG,YAAY,UAAU;AAExD,YAAI,CAAC;AACH;AAGF,cAAM,mBAAmB,uBAAuB,GAAG,YAAY,eAAe,OAAO,GAC/E,gBAAgB,uBAAuB,YAAY,IAAI;AAEzD,yBAAiB,iBAAiB,IAAI,aAAa,KACrD,QAAQ,IAAI,SAAS;AAAA,MAEzB;AAAA,EACF,CAAC,GAEM;AACT;AAEO,SAAS,0BACd,GACA,MACA,eACA,UACA,YACA,SACa;AACb,QAAM,WAAW,kCAAkC,GAAG,MAAM,UAAU,GAChE,WAAW,kCAAkC,GAAG,MAAM,eAAe,UAAU,OAAO;AAE5F,6BAAW,IAAI,CAAC,GAAG,UAAU,GAAG,QAAQ,CAAC;AAC3C;AC3GA,MAAM,kBAAkB;AAOjB,SAAS,0BACd,GACA,MACA,SACA,QACA,UAGI,IACK;AACT,QAAM,QAAQ,IAAI,IAAI,OAAO,GACvB,EAAC,UAAU,UAAU,gBAAA,IAAmB;AAC9C,MAAI,aAAa;AAEjB,SAAA,KAAK,KAAK,EAAE,iBAAiB,EAAE,QAAQ,CAAC,SAAS;AAC/C,UAAM,OAAO,KAAK,KAAK;AAEvB,QAAI,KAAK,SAAS,mBAAmB,CAAC,MAAM,IAAI,KAAK,IAAI;AACvD;AAGF,UAAM,QAAQ,KAAK,KAAK,cAAc,CAAA;AAEtC,QAAI,CAAC,OAAO,KAAK,GAAG;AACd,wBAAkB,GAAG,MAAM,OAAO,MACpC,aAAa;AAGf;AAAA,IACF;AAEI,eAAW,IAAI,MACjB,aAAa;AAAA,EAEjB,CAAC,GAEM;AACT;AC5CO,MAAM,YAA2B;AAAA,EACtC,GAAG;AAAA,EACH,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,EAAA;AAAA,EAER,WAAW;AAAA,IACT,MAAM;AAAA,IACN,MAAM;AAAA,EAAA;AAAA,EAER,iBAAiB;AAAA,IACf,MAAM;AAAA,IACN,OAAO;AAAA,EAAA;AAAA,EAET,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,OAAO;AAAA,EAAA;AAAA,EAET,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,OAAO;AAAA,EAAA;AAAA,EAET,qBAAqB;AAAA,IACnB,MAAM;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,MACP,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IAAA;AAAA,EACN;AAAA,EAEF,kBAAkB;AAAA,IAChB,MAAM;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,MACP,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IAAA;AAAA,EACN;AAAA,EAEF,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,EAAA;AAAA,EAER,SAAS;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,EAAA;AAEV;"}
|
|
@@ -1,154 +1,8 @@
|
|
|
1
1
|
import "jscodeshift";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { resolve, dirname, join } from "node:path";
|
|
2
|
+
import { transformComponent, getComponentLocalNames, shouldTransformComponent, transformImport, transformAttributes, getStaticAttributeExpression } from "../../../_chunks-es/transformComponent.js";
|
|
3
|
+
import { getStyledComponentAliases, FLEX_MODS, transformStyledComponents } from "../../../_chunks-es/flex.mods.js";
|
|
5
4
|
import { replaceElement, BOX_MODS } from "../../../_chunks-es/box.mods.js";
|
|
6
|
-
import { FLEX_MODS } from "../../../_chunks-es/flex.mods.js";
|
|
7
5
|
import { GRID_MODS } from "../../../_chunks-es/grid.mods.js";
|
|
8
|
-
const parseCache = /* @__PURE__ */ new Map();
|
|
9
|
-
function parseModule(j, filePath) {
|
|
10
|
-
const cached = parseCache.get(filePath);
|
|
11
|
-
if (cached)
|
|
12
|
-
return cached;
|
|
13
|
-
try {
|
|
14
|
-
const source = readFileSync(filePath, "utf8"), root = j(source);
|
|
15
|
-
return parseCache.set(filePath, root), root;
|
|
16
|
-
} catch {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
const EXTENSIONS = [".tsx", ".ts", ".jsx", ".js"];
|
|
21
|
-
function resolveRelativeModulePath(fromFilePath, moduleSpecifier) {
|
|
22
|
-
if (!moduleSpecifier.startsWith("."))
|
|
23
|
-
return null;
|
|
24
|
-
const base = resolve(dirname(fromFilePath), moduleSpecifier);
|
|
25
|
-
for (const ext of EXTENSIONS) {
|
|
26
|
-
const filePath = `${base}${ext}`;
|
|
27
|
-
if (existsSync(filePath))
|
|
28
|
-
return filePath;
|
|
29
|
-
}
|
|
30
|
-
for (const ext of EXTENSIONS) {
|
|
31
|
-
const indexPath = join(base, `index${ext}`);
|
|
32
|
-
if (existsSync(indexPath))
|
|
33
|
-
return indexPath;
|
|
34
|
-
}
|
|
35
|
-
return existsSync(base) ? base : null;
|
|
36
|
-
}
|
|
37
|
-
function findVariableInit(j, root, name) {
|
|
38
|
-
let init = null;
|
|
39
|
-
return root.find(j.VariableDeclarator).forEach((path) => {
|
|
40
|
-
const { id } = path.node;
|
|
41
|
-
id.type === "Identifier" && id.name === name && path.node.init && (init = path.node.init);
|
|
42
|
-
}), init;
|
|
43
|
-
}
|
|
44
|
-
function getExportSpecifierName(exported) {
|
|
45
|
-
return exported.type === "Identifier" || exported.type === "JSXIdentifier" ? exported.name : null;
|
|
46
|
-
}
|
|
47
|
-
function getNamedExportInit(j, exportName, filePath, visited = /* @__PURE__ */ new Set()) {
|
|
48
|
-
if (visited.has(filePath))
|
|
49
|
-
return null;
|
|
50
|
-
visited.add(filePath);
|
|
51
|
-
const root = parseModule(j, filePath);
|
|
52
|
-
if (!root)
|
|
53
|
-
return null;
|
|
54
|
-
for (const path of root.find(j.ExportNamedDeclaration).paths()) {
|
|
55
|
-
const { declaration, specifiers, source } = path.node, reexportSource = typeof source?.value == "string" ? source.value : null;
|
|
56
|
-
if (declaration?.type === "VariableDeclaration") {
|
|
57
|
-
for (const declarator of declaration.declarations)
|
|
58
|
-
if (declarator.type === "VariableDeclarator" && declarator.id.type === "Identifier" && declarator.id.name === exportName && declarator.init)
|
|
59
|
-
return { init: declarator.init, modulePath: filePath };
|
|
60
|
-
}
|
|
61
|
-
for (const spec of specifiers ?? []) {
|
|
62
|
-
if (spec.type !== "ExportSpecifier")
|
|
63
|
-
continue;
|
|
64
|
-
const exported = getExportSpecifierName(spec.exported);
|
|
65
|
-
if (!exported || exported !== exportName)
|
|
66
|
-
continue;
|
|
67
|
-
const local = spec.local?.type === "Identifier" ? spec.local.name : exported;
|
|
68
|
-
if (reexportSource) {
|
|
69
|
-
const resolvedPath = resolveRelativeModulePath(filePath, reexportSource);
|
|
70
|
-
if (resolvedPath) {
|
|
71
|
-
const followed = getNamedExportInit(j, local, resolvedPath, visited);
|
|
72
|
-
if (followed)
|
|
73
|
-
return followed;
|
|
74
|
-
}
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
const init = findVariableInit(j, root, local);
|
|
78
|
-
if (init)
|
|
79
|
-
return { init, modulePath: filePath };
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
function getStyledComponentName(node) {
|
|
85
|
-
if (!node || typeof node != "object" || !("type" in node))
|
|
86
|
-
return null;
|
|
87
|
-
const current = node;
|
|
88
|
-
if (current.type === "TaggedTemplateExpression")
|
|
89
|
-
return getStyledComponentName(current.tag);
|
|
90
|
-
if (current.type === "CallExpression") {
|
|
91
|
-
const callee = current.callee;
|
|
92
|
-
if (callee && typeof callee == "object" && "type" in callee && callee.type === "Identifier" && "name" in callee && callee.name === "styled") {
|
|
93
|
-
const arg = current.arguments?.[0];
|
|
94
|
-
return arg && typeof arg == "object" && "type" in arg && arg.type === "Identifier" && "name" in arg ? arg.name : null;
|
|
95
|
-
}
|
|
96
|
-
return getStyledComponentName(callee);
|
|
97
|
-
}
|
|
98
|
-
return current.type === "MemberExpression" && current.object ? getStyledComponentName(current.object) : null;
|
|
99
|
-
}
|
|
100
|
-
function getSameFileStyledComponentAliases(j, root, localNames) {
|
|
101
|
-
const aliases = /* @__PURE__ */ new Set(), names = new Set(localNames);
|
|
102
|
-
return root.find(j.VariableDeclarator).forEach((path) => {
|
|
103
|
-
const { id, init } = path.node;
|
|
104
|
-
if (!init || id.type !== "Identifier")
|
|
105
|
-
return;
|
|
106
|
-
const baseComponent = getStyledComponentName(init);
|
|
107
|
-
baseComponent && names.has(baseComponent) && aliases.add(id.name);
|
|
108
|
-
}), aliases;
|
|
109
|
-
}
|
|
110
|
-
function getImportedStyledComponentAliases(j, root, componentName, filePath, options) {
|
|
111
|
-
const aliases = /* @__PURE__ */ new Set();
|
|
112
|
-
return filePath && root.find(j.ImportDeclaration).forEach((path) => {
|
|
113
|
-
const source = path.node.source.value;
|
|
114
|
-
if (typeof source != "string")
|
|
115
|
-
return;
|
|
116
|
-
const resolvedPath = resolveRelativeModulePath(filePath, source);
|
|
117
|
-
if (resolvedPath)
|
|
118
|
-
for (const spec of path.node.specifiers ?? []) {
|
|
119
|
-
if (spec.type !== "ImportSpecifier" || "importKind" in spec && spec.importKind === "type" || spec.imported.type !== "Identifier")
|
|
120
|
-
continue;
|
|
121
|
-
const exportName = spec.imported.name, localName = spec.local?.type === "Identifier" ? spec.local.name : exportName, namedExport = getNamedExportInit(j, exportName, resolvedPath);
|
|
122
|
-
if (!namedExport)
|
|
123
|
-
continue;
|
|
124
|
-
const sourceRoot = parseModule(j, namedExport.modulePath);
|
|
125
|
-
if (!sourceRoot)
|
|
126
|
-
continue;
|
|
127
|
-
const exportLocalNames = getComponentLocalNames(j, sourceRoot, componentName, options), baseComponent = getStyledComponentName(namedExport.init);
|
|
128
|
-
baseComponent && exportLocalNames.has(baseComponent) && aliases.add(localName);
|
|
129
|
-
}
|
|
130
|
-
}), aliases;
|
|
131
|
-
}
|
|
132
|
-
function getStyledComponentAliases(j, root, componentName, filePath, localNames, options) {
|
|
133
|
-
const sameFile = getSameFileStyledComponentAliases(j, root, localNames), imported = getImportedStyledComponentAliases(j, root, componentName, filePath, options);
|
|
134
|
-
return /* @__PURE__ */ new Set([...sameFile, ...imported]);
|
|
135
|
-
}
|
|
136
|
-
const DEFAULT_WARNING = "Please double check styled-component migration below";
|
|
137
|
-
function transformStyledComponents(j, root, aliases, filter, options = {}) {
|
|
138
|
-
const names = new Set(aliases), { callback, warning = DEFAULT_WARNING } = options;
|
|
139
|
-
let hasChanges = !1;
|
|
140
|
-
return root.find(j.JSXOpeningElement).forEach((path) => {
|
|
141
|
-
const name = path.node.name;
|
|
142
|
-
if (name.type !== "JSXIdentifier" || !names.has(name.name))
|
|
143
|
-
return;
|
|
144
|
-
const attrs = path.node.attributes ?? [];
|
|
145
|
-
if (!filter(attrs)) {
|
|
146
|
-
insertTodoWarning(j, path, warning) && (hasChanges = !0);
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
callback?.(path) && (hasChanges = !0);
|
|
150
|
-
}), hasChanges;
|
|
151
|
-
}
|
|
152
6
|
const BOX_TODO_WARNING = "Please double check the Box migration below", FLEX_TODO_WARNING = "Please double check the Flex migration below", GRID_TODO_WARNING = "Please double check the Grid migration below", STYLED_TODO_WARNING = "Please double check styled(Box) migration below";
|
|
153
7
|
function transform(fileInfo, api, options) {
|
|
154
8
|
const { fromPackage, toPackage } = options || {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"box.js","sources":["../../../../src/utils/parseModule.ts","../../../../src/utils/resolveRelativeModulePath.ts","../../../../src/utils/getNamedExportInit.ts","../../../../src/utils/getStyledComponentName.ts","../../../../src/utils/getStyledComponentAliases.ts","../../../../src/utils/transformStyledComponents.ts","../../../../src/transforms/latest/box/box.ts"],"sourcesContent":["import {readFileSync} from 'node:fs'\n\nimport type {API, Collection} from 'jscodeshift'\n\nconst parseCache = new Map<string, Collection>()\n\nexport function parseModule(j: API['jscodeshift'], filePath: string): Collection | null {\n const cached = parseCache.get(filePath)\n\n if (cached) {\n return cached\n }\n\n try {\n const source = readFileSync(filePath, 'utf8')\n const root = j(source)\n\n parseCache.set(filePath, root)\n\n return root\n } catch {\n return null\n }\n}\n\n/** @internal */\nexport function clearModuleParseCache(): void {\n parseCache.clear()\n}\n","import {existsSync} from 'node:fs'\nimport {dirname, join, resolve} from 'node:path'\n\nconst EXTENSIONS = ['.tsx', '.ts', '.jsx', '.js'] as const\n\nexport function resolveRelativeModulePath(\n fromFilePath: string,\n moduleSpecifier: string,\n): string | null {\n if (!moduleSpecifier.startsWith('.')) {\n return null\n }\n\n const base = resolve(dirname(fromFilePath), moduleSpecifier)\n\n for (const ext of EXTENSIONS) {\n const filePath = `${base}${ext}`\n\n if (existsSync(filePath)) {\n return filePath\n }\n }\n\n for (const ext of EXTENSIONS) {\n const indexPath = join(base, `index${ext}`)\n\n if (existsSync(indexPath)) {\n return indexPath\n }\n }\n\n if (existsSync(base)) {\n return base\n }\n\n return null\n}\n","import type {API, Expression, ExportSpecifier} from 'jscodeshift'\n\nimport {parseModule} from './parseModule'\nimport {resolveRelativeModulePath} from './resolveRelativeModulePath'\n\nexport type NamedExportInit = {\n init: Expression\n modulePath: string\n}\n\nfunction findVariableInit(\n j: API['jscodeshift'],\n root: ReturnType<API['jscodeshift']>,\n name: string,\n): Expression | null {\n let init: Expression | null = null\n\n root.find(j.VariableDeclarator).forEach((path) => {\n const {id} = path.node\n\n if (id.type === 'Identifier' && id.name === name && path.node.init) {\n init = path.node.init\n }\n })\n\n return init\n}\n\nfunction getExportSpecifierName(exported: ExportSpecifier['exported']): string | null {\n if (exported.type === 'Identifier' || exported.type === 'JSXIdentifier') {\n return exported.name\n }\n\n return null\n}\n\nexport function getNamedExportInit(\n j: API['jscodeshift'],\n exportName: string,\n filePath: string,\n visited: Set<string> = new Set(),\n): NamedExportInit | null {\n if (visited.has(filePath)) {\n return null\n }\n\n visited.add(filePath)\n\n const root = parseModule(j, filePath)\n\n if (!root) {\n return null\n }\n\n for (const path of root.find(j.ExportNamedDeclaration).paths()) {\n const {declaration, specifiers, source} = path.node\n const reexportSource = typeof source?.value === 'string' ? source.value : null\n\n if (declaration?.type === 'VariableDeclaration') {\n for (const declarator of declaration.declarations) {\n if (declarator.type !== 'VariableDeclarator') {\n continue\n }\n\n if (\n declarator.id.type === 'Identifier' &&\n declarator.id.name === exportName &&\n declarator.init\n ) {\n return {init: declarator.init, modulePath: filePath}\n }\n }\n }\n\n for (const spec of specifiers ?? []) {\n if (spec.type !== 'ExportSpecifier') {\n continue\n }\n\n const exported = getExportSpecifierName(spec.exported)\n\n if (!exported || exported !== exportName) {\n continue\n }\n\n const local = spec.local?.type === 'Identifier' ? spec.local.name : exported\n\n if (reexportSource) {\n const resolvedPath = resolveRelativeModulePath(filePath, reexportSource)\n\n if (resolvedPath) {\n const followed = getNamedExportInit(j, local, resolvedPath, visited)\n\n if (followed) {\n return followed\n }\n }\n\n continue\n }\n\n const init = findVariableInit(j, root, local)\n\n if (init) {\n return {init, modulePath: filePath}\n }\n }\n }\n\n return null\n}\n","export function getStyledComponentName(node: unknown): string | null {\n if (!node || typeof node !== 'object' || !('type' in node)) {\n return null\n }\n\n const current = node as {\n type: string\n callee?: unknown\n tag?: unknown\n object?: unknown\n arguments?: unknown[]\n }\n\n if (current.type === 'TaggedTemplateExpression') {\n return getStyledComponentName(current.tag)\n }\n\n if (current.type === 'CallExpression') {\n const callee = current.callee\n\n if (\n callee &&\n typeof callee === 'object' &&\n 'type' in callee &&\n callee.type === 'Identifier' &&\n 'name' in callee &&\n callee.name === 'styled'\n ) {\n const arg = current.arguments?.[0]\n\n if (\n arg &&\n typeof arg === 'object' &&\n 'type' in arg &&\n arg.type === 'Identifier' &&\n 'name' in arg\n ) {\n return arg.name as string\n }\n\n return null\n }\n\n return getStyledComponentName(callee)\n }\n\n if (current.type === 'MemberExpression' && current.object) {\n return getStyledComponentName(current.object)\n }\n\n return null\n}\n","import type {API, Collection} from 'jscodeshift'\n\nimport type {BaseOptions} from '../types/BaseOptions'\nimport {getComponentLocalNames} from './getComponentLocalNames'\nimport {getNamedExportInit} from './getNamedExportInit'\nimport {getStyledComponentName} from './getStyledComponentName'\nimport {parseModule} from './parseModule'\nimport {resolveRelativeModulePath} from './resolveRelativeModulePath'\n\nexport function getSameFileStyledComponentAliases(\n j: API['jscodeshift'],\n root: Collection,\n localNames: Iterable<string>,\n): Set<string> {\n const aliases = new Set<string>()\n const names = new Set(localNames)\n\n root.find(j.VariableDeclarator).forEach((path) => {\n const {id, init} = path.node\n\n if (!init || id.type !== 'Identifier') {\n return\n }\n\n const baseComponent = getStyledComponentName(init)\n\n if (baseComponent && names.has(baseComponent)) {\n aliases.add(id.name)\n }\n })\n\n return aliases\n}\n\nexport function getImportedStyledComponentAliases(\n j: API['jscodeshift'],\n root: Collection,\n componentName: string,\n filePath: string | undefined,\n options?: BaseOptions,\n): Set<string> {\n const aliases = new Set<string>()\n\n if (!filePath) {\n return aliases\n }\n\n root.find(j.ImportDeclaration).forEach((path) => {\n const source = path.node.source.value\n\n if (typeof source !== 'string') {\n return\n }\n\n const resolvedPath = resolveRelativeModulePath(filePath, source)\n\n if (!resolvedPath) {\n return\n }\n\n for (const spec of path.node.specifiers ?? []) {\n if (spec.type !== 'ImportSpecifier') {\n continue\n }\n\n if ('importKind' in spec && spec.importKind === 'type') {\n continue\n }\n\n if (spec.imported.type !== 'Identifier') {\n continue\n }\n\n const exportName = spec.imported.name\n const localName = spec.local?.type === 'Identifier' ? spec.local.name : exportName\n const namedExport = getNamedExportInit(j, exportName, resolvedPath)\n\n if (!namedExport) {\n continue\n }\n\n const sourceRoot = parseModule(j, namedExport.modulePath)\n\n if (!sourceRoot) {\n continue\n }\n\n const exportLocalNames = getComponentLocalNames(j, sourceRoot, componentName, options)\n const baseComponent = getStyledComponentName(namedExport.init)\n\n if (baseComponent && exportLocalNames.has(baseComponent)) {\n aliases.add(localName)\n }\n }\n })\n\n return aliases\n}\n\nexport function getStyledComponentAliases(\n j: API['jscodeshift'],\n root: Collection,\n componentName: string,\n filePath: string | undefined,\n localNames: Set<string>,\n options?: BaseOptions,\n): Set<string> {\n const sameFile = getSameFileStyledComponentAliases(j, root, localNames)\n const imported = getImportedStyledComponentAliases(j, root, componentName, filePath, options)\n\n return new Set([...sameFile, ...imported])\n}\n","import type {API, ASTPath, JSXAttribute, JSXOpeningElement, JSXSpreadAttribute} from 'jscodeshift'\n\nimport {insertTodoWarning} from './insertTodoWarning'\n\nconst DEFAULT_WARNING = 'Please double check styled-component migration below'\n\n/**\n * Runs callback on JSX styled-component if `filter` passes. Otherwise, adds\n * a TODO on the component JSX instance when manual review is needed.\n * Returns whether the AST was updated.\n */\nexport function transformStyledComponents(\n j: API['jscodeshift'],\n root: ReturnType<API['jscodeshift']>,\n aliases: Iterable<string>,\n filter: (attrs: (JSXAttribute | JSXSpreadAttribute)[]) => boolean,\n options: {\n callback?: (path: ASTPath<JSXOpeningElement>) => boolean | void\n warning?: string\n } = {},\n): boolean {\n const names = new Set(aliases)\n const {callback, warning = DEFAULT_WARNING} = options\n let hasChanges = false\n\n root.find(j.JSXOpeningElement).forEach((path) => {\n const name = path.node.name\n\n if (name.type !== 'JSXIdentifier' || !names.has(name.name)) {\n return\n }\n\n const attrs = path.node.attributes ?? []\n\n if (!filter(attrs)) {\n if (insertTodoWarning(j, path, warning)) {\n hasChanges = true\n }\n\n return\n }\n\n if (callback?.(path)) {\n hasChanges = true\n }\n })\n\n return hasChanges\n}\n","import {type API, type FileInfo, type JSXSpreadAttribute, type JSXAttribute} from 'jscodeshift'\n\nimport type {BaseOptions} from '../../../types/BaseOptions'\nimport {getComponentLocalNames} from '../../../utils/getComponentLocalNames'\nimport {getStaticAttributeExpression} from '../../../utils/getStaticAttributeExpression'\nimport {getStyledComponentAliases} from '../../../utils/getStyledComponentAliases'\nimport {replaceElement} from '../../../utils/replaceElement'\nimport {shouldTransformComponent} from '../../../utils/shouldTransformComponent'\nimport {transformAttributes} from '../../../utils/transformAttributes'\nimport {transformComponent} from '../../../utils/transformComponent'\nimport {transformImport} from '../../../utils/transformImport'\nimport {transformStyledComponents} from '../../../utils/transformStyledComponents'\nimport {FLEX_MODS} from '../flex/flex.mods'\nimport {GRID_MODS} from '../grid/grid.mods'\nimport {BOX_MODS} from './box.mods'\n\nconst BOX_TODO_WARNING = 'Please double check the Box migration below'\nconst FLEX_TODO_WARNING = 'Please double check the Flex migration below'\nconst GRID_TODO_WARNING = 'Please double check the Grid migration below'\nconst STYLED_TODO_WARNING = 'Please double check styled(Box) migration below'\n\n/** @internal */\nexport default function transform(\n fileInfo: FileInfo,\n api: API,\n options?: BaseOptions,\n): string | undefined {\n const {fromPackage, toPackage} = options || {}\n\n return transformComponent(fileInfo, api, ({j, root, markChanged}) => {\n const localNames = getComponentLocalNames(j, root, 'Box', options)\n const styledAliases = getStyledComponentAliases(\n j,\n root,\n 'Box',\n fileInfo.path,\n localNames,\n options,\n )\n\n if (!shouldTransformComponent(j, root, 'Box', localNames, options, styledAliases)) {\n return\n }\n\n const matchesDisplayValue = (\n attrs: (JSXAttribute | JSXSpreadAttribute)[],\n suffix: string,\n exclude: string[],\n ) => {\n const display = getStaticAttributeExpression(j, attrs, 'display') || []\n const values = Array.isArray(display) ? display : [display]\n let matchesExclude\n\n for (const excluded of exclude) {\n if (values.some((value) => typeof value === 'string' && value.endsWith(excluded))) {\n matchesExclude = true\n break\n }\n }\n\n if (matchesExclude) {\n return false\n }\n\n return values.some((value) => typeof value === 'string' && value.endsWith(suffix))\n }\n\n const replaceWithFlex = (attrs: (JSXAttribute | JSXSpreadAttribute)[]) =>\n matchesDisplayValue(attrs, 'flex', ['block', 'inline', 'grid'])\n\n const replaceWithGrid = (attrs: (JSXAttribute | JSXSpreadAttribute)[]) =>\n matchesDisplayValue(attrs, 'grid', ['block', 'inline', 'flex'])\n\n if (transformImport(j, root, 'Box', fromPackage, toPackage)) {\n markChanged()\n }\n\n if (\n replaceElement(\n j,\n root,\n replaceWithFlex,\n {\n element: 'Box',\n localNames,\n },\n {\n element: 'Flex',\n callback: (path) => transformAttributes(j, path, FLEX_MODS, FLEX_TODO_WARNING),\n },\n )\n ) {\n markChanged()\n }\n\n if (\n replaceElement(\n j,\n root,\n replaceWithGrid,\n {\n element: 'Box',\n localNames,\n callback: (path) => transformAttributes(j, path, BOX_MODS, BOX_TODO_WARNING),\n },\n {\n element: 'Grid',\n callback: (path) => transformAttributes(j, path, GRID_MODS, GRID_TODO_WARNING),\n },\n )\n ) {\n markChanged()\n }\n\n if (\n transformStyledComponents(\n j,\n root,\n styledAliases,\n (attrs) => !replaceWithFlex(attrs) && !replaceWithGrid(attrs),\n {\n warning: STYLED_TODO_WARNING,\n callback: (path) => transformAttributes(j, path, BOX_MODS, BOX_TODO_WARNING),\n },\n )\n ) {\n markChanged()\n }\n })\n}\n"],"names":[],"mappings":";;;;;;;AAIA,MAAM,iCAAiB,IAAA;AAEhB,SAAS,YAAY,GAAuB,UAAqC;AACtF,QAAM,SAAS,WAAW,IAAI,QAAQ;AAEtC,MAAI;AACF,WAAO;AAGT,MAAI;AACF,UAAM,SAAS,aAAa,UAAU,MAAM,GACtC,OAAO,EAAE,MAAM;AAErB,WAAA,WAAW,IAAI,UAAU,IAAI,GAEtB;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;ACpBA,MAAM,aAAa,CAAC,QAAQ,OAAO,QAAQ,KAAK;AAEzC,SAAS,0BACd,cACA,iBACe;AACf,MAAI,CAAC,gBAAgB,WAAW,GAAG;AACjC,WAAO;AAGT,QAAM,OAAO,QAAQ,QAAQ,YAAY,GAAG,eAAe;AAE3D,aAAW,OAAO,YAAY;AAC5B,UAAM,WAAW,GAAG,IAAI,GAAG,GAAG;AAE9B,QAAI,WAAW,QAAQ;AACrB,aAAO;AAAA,EAEX;AAEA,aAAW,OAAO,YAAY;AAC5B,UAAM,YAAY,KAAK,MAAM,QAAQ,GAAG,EAAE;AAE1C,QAAI,WAAW,SAAS;AACtB,aAAO;AAAA,EAEX;AAEA,SAAI,WAAW,IAAI,IACV,OAGF;AACT;AC1BA,SAAS,iBACP,GACA,MACA,MACmB;AACnB,MAAI,OAA0B;AAE9B,SAAA,KAAK,KAAK,EAAE,kBAAkB,EAAE,QAAQ,CAAC,SAAS;AAChD,UAAM,EAAC,OAAM,KAAK;AAEd,OAAG,SAAS,gBAAgB,GAAG,SAAS,QAAQ,KAAK,KAAK,SAC5D,OAAO,KAAK,KAAK;AAAA,EAErB,CAAC,GAEM;AACT;AAEA,SAAS,uBAAuB,UAAsD;AACpF,SAAI,SAAS,SAAS,gBAAgB,SAAS,SAAS,kBAC/C,SAAS,OAGX;AACT;AAEO,SAAS,mBACd,GACA,YACA,UACA,UAAuB,oBAAI,OACH;AACxB,MAAI,QAAQ,IAAI,QAAQ;AACtB,WAAO;AAGT,UAAQ,IAAI,QAAQ;AAEpB,QAAM,OAAO,YAAY,GAAG,QAAQ;AAEpC,MAAI,CAAC;AACH,WAAO;AAGT,aAAW,QAAQ,KAAK,KAAK,EAAE,sBAAsB,EAAE,SAAS;AAC9D,UAAM,EAAC,aAAa,YAAY,OAAA,IAAU,KAAK,MACzC,iBAAiB,OAAO,QAAQ,SAAU,WAAW,OAAO,QAAQ;AAE1E,QAAI,aAAa,SAAS;AACxB,iBAAW,cAAc,YAAY;AACnC,YAAI,WAAW,SAAS,wBAKtB,WAAW,GAAG,SAAS,gBACvB,WAAW,GAAG,SAAS,cACvB,WAAW;AAEX,iBAAO,EAAC,MAAM,WAAW,MAAM,YAAY,SAAA;AAAA;AAKjD,eAAW,QAAQ,cAAc,IAAI;AACnC,UAAI,KAAK,SAAS;AAChB;AAGF,YAAM,WAAW,uBAAuB,KAAK,QAAQ;AAErD,UAAI,CAAC,YAAY,aAAa;AAC5B;AAGF,YAAM,QAAQ,KAAK,OAAO,SAAS,eAAe,KAAK,MAAM,OAAO;AAEpE,UAAI,gBAAgB;AAClB,cAAM,eAAe,0BAA0B,UAAU,cAAc;AAEvE,YAAI,cAAc;AAChB,gBAAM,WAAW,mBAAmB,GAAG,OAAO,cAAc,OAAO;AAEnE,cAAI;AACF,mBAAO;AAAA,QAEX;AAEA;AAAA,MACF;AAEA,YAAM,OAAO,iBAAiB,GAAG,MAAM,KAAK;AAE5C,UAAI;AACF,eAAO,EAAC,MAAM,YAAY,SAAA;AAAA,IAE9B;AAAA,EACF;AAEA,SAAO;AACT;AC9GO,SAAS,uBAAuB,MAA8B;AACnE,MAAI,CAAC,QAAQ,OAAO,QAAS,YAAY,EAAE,UAAU;AACnD,WAAO;AAGT,QAAM,UAAU;AAQhB,MAAI,QAAQ,SAAS;AACnB,WAAO,uBAAuB,QAAQ,GAAG;AAG3C,MAAI,QAAQ,SAAS,kBAAkB;AACrC,UAAM,SAAS,QAAQ;AAEvB,QACE,UACA,OAAO,UAAW,YAClB,UAAU,UACV,OAAO,SAAS,gBAChB,UAAU,UACV,OAAO,SAAS,UAChB;AACA,YAAM,MAAM,QAAQ,YAAY,CAAC;AAEjC,aACE,OACA,OAAO,OAAQ,YACf,UAAU,OACV,IAAI,SAAS,gBACb,UAAU,MAEH,IAAI,OAGN;AAAA,IACT;AAEA,WAAO,uBAAuB,MAAM;AAAA,EACtC;AAEA,SAAI,QAAQ,SAAS,sBAAsB,QAAQ,SAC1C,uBAAuB,QAAQ,MAAM,IAGvC;AACT;AC1CO,SAAS,kCACd,GACA,MACA,YACa;AACb,QAAM,UAAU,oBAAI,IAAA,GACd,QAAQ,IAAI,IAAI,UAAU;AAEhC,SAAA,KAAK,KAAK,EAAE,kBAAkB,EAAE,QAAQ,CAAC,SAAS;AAChD,UAAM,EAAC,IAAI,KAAA,IAAQ,KAAK;AAExB,QAAI,CAAC,QAAQ,GAAG,SAAS;AACvB;AAGF,UAAM,gBAAgB,uBAAuB,IAAI;AAE7C,qBAAiB,MAAM,IAAI,aAAa,KAC1C,QAAQ,IAAI,GAAG,IAAI;AAAA,EAEvB,CAAC,GAEM;AACT;AAEO,SAAS,kCACd,GACA,MACA,eACA,UACA,SACa;AACb,QAAM,8BAAc,IAAA;AAEpB,SAAK,YAIL,KAAK,KAAK,EAAE,iBAAiB,EAAE,QAAQ,CAAC,SAAS;AAC/C,UAAM,SAAS,KAAK,KAAK,OAAO;AAEhC,QAAI,OAAO,UAAW;AACpB;AAGF,UAAM,eAAe,0BAA0B,UAAU,MAAM;AAE/D,QAAK;AAIL,iBAAW,QAAQ,KAAK,KAAK,cAAc,CAAA,GAAI;AAS7C,YARI,KAAK,SAAS,qBAId,gBAAgB,QAAQ,KAAK,eAAe,UAI5C,KAAK,SAAS,SAAS;AACzB;AAGF,cAAM,aAAa,KAAK,SAAS,MAC3B,YAAY,KAAK,OAAO,SAAS,eAAe,KAAK,MAAM,OAAO,YAClE,cAAc,mBAAmB,GAAG,YAAY,YAAY;AAElE,YAAI,CAAC;AACH;AAGF,cAAM,aAAa,YAAY,GAAG,YAAY,UAAU;AAExD,YAAI,CAAC;AACH;AAGF,cAAM,mBAAmB,uBAAuB,GAAG,YAAY,eAAe,OAAO,GAC/E,gBAAgB,uBAAuB,YAAY,IAAI;AAEzD,yBAAiB,iBAAiB,IAAI,aAAa,KACrD,QAAQ,IAAI,SAAS;AAAA,MAEzB;AAAA,EACF,CAAC,GAEM;AACT;AAEO,SAAS,0BACd,GACA,MACA,eACA,UACA,YACA,SACa;AACb,QAAM,WAAW,kCAAkC,GAAG,MAAM,UAAU,GAChE,WAAW,kCAAkC,GAAG,MAAM,eAAe,UAAU,OAAO;AAE5F,6BAAW,IAAI,CAAC,GAAG,UAAU,GAAG,QAAQ,CAAC;AAC3C;AC3GA,MAAM,kBAAkB;AAOjB,SAAS,0BACd,GACA,MACA,SACA,QACA,UAGI,IACK;AACT,QAAM,QAAQ,IAAI,IAAI,OAAO,GACvB,EAAC,UAAU,UAAU,gBAAA,IAAmB;AAC9C,MAAI,aAAa;AAEjB,SAAA,KAAK,KAAK,EAAE,iBAAiB,EAAE,QAAQ,CAAC,SAAS;AAC/C,UAAM,OAAO,KAAK,KAAK;AAEvB,QAAI,KAAK,SAAS,mBAAmB,CAAC,MAAM,IAAI,KAAK,IAAI;AACvD;AAGF,UAAM,QAAQ,KAAK,KAAK,cAAc,CAAA;AAEtC,QAAI,CAAC,OAAO,KAAK,GAAG;AACd,wBAAkB,GAAG,MAAM,OAAO,MACpC,aAAa;AAGf;AAAA,IACF;AAEI,eAAW,IAAI,MACjB,aAAa;AAAA,EAEjB,CAAC,GAEM;AACT;AChCA,MAAM,mBAAmB,+CACnB,oBAAoB,gDACpB,oBAAoB,gDACpB,sBAAsB;AAG5B,SAAwB,UACtB,UACA,KACA,SACoB;AACpB,QAAM,EAAC,aAAa,UAAA,IAAa,WAAW,CAAA;AAE5C,SAAO,mBAAmB,UAAU,KAAK,CAAC,EAAC,GAAG,MAAM,kBAAiB;AACnE,UAAM,aAAa,uBAAuB,GAAG,MAAM,OAAO,OAAO,GAC3D,gBAAgB;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA;AAAA,IAAA;AAGF,QAAI,CAAC,yBAAyB,GAAG,MAAM,OAAO,YAAY,SAAS,aAAa;AAC9E;AAGF,UAAM,sBAAsB,CAC1B,OACA,QACA,YACG;AACH,YAAM,UAAU,6BAA6B,GAAG,OAAO,SAAS,KAAK,CAAA,GAC/D,SAAS,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC,OAAO;AAC1D,UAAI;AAEJ,iBAAW,YAAY;AACrB,YAAI,OAAO,KAAK,CAAC,UAAU,OAAO,SAAU,YAAY,MAAM,SAAS,QAAQ,CAAC,GAAG;AACjF,2BAAiB;AACjB;AAAA,QACF;AAGF,aAAI,iBACK,KAGF,OAAO,KAAK,CAAC,UAAU,OAAO,SAAU,YAAY,MAAM,SAAS,MAAM,CAAC;AAAA,IACnF,GAEM,kBAAkB,CAAC,UACvB,oBAAoB,OAAO,QAAQ,CAAC,SAAS,UAAU,MAAM,CAAC,GAE1D,kBAAkB,CAAC,UACvB,oBAAoB,OAAO,QAAQ,CAAC,SAAS,UAAU,MAAM,CAAC;AAE5D,oBAAgB,GAAG,MAAM,OAAO,aAAa,SAAS,KACxD,eAIA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,QACE,SAAS;AAAA,QACT;AAAA,MAAA;AAAA,MAEF;AAAA,QACE,SAAS;AAAA,QACT,UAAU,CAAC,SAAS,oBAAoB,GAAG,MAAM,WAAW,iBAAiB;AAAA,MAAA;AAAA,IAC/E,KAGF,eAIA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,QACE,SAAS;AAAA,QACT;AAAA,QACA,UAAU,CAAC,SAAS,oBAAoB,GAAG,MAAM,UAAU,gBAAgB;AAAA,MAAA;AAAA,MAE7E;AAAA,QACE,SAAS;AAAA,QACT,UAAU,CAAC,SAAS,oBAAoB,GAAG,MAAM,WAAW,iBAAiB;AAAA,MAAA;AAAA,IAC/E,KAGF,eAIA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA,CAAC,UAAU,CAAC,gBAAgB,KAAK,KAAK,CAAC,gBAAgB,KAAK;AAAA,MAC5D;AAAA,QACE,SAAS;AAAA,QACT,UAAU,CAAC,SAAS,oBAAoB,GAAG,MAAM,UAAU,gBAAgB;AAAA,MAAA;AAAA,IAC7E,KAGF,YAAA;AAAA,EAEJ,CAAC;AACH;"}
|
|
1
|
+
{"version":3,"file":"box.js","sources":["../../../../src/transforms/latest/box/box.ts"],"sourcesContent":["import {type API, type FileInfo, type JSXSpreadAttribute, type JSXAttribute} from 'jscodeshift'\n\nimport type {BaseOptions} from '../../../types/BaseOptions'\nimport {getComponentLocalNames} from '../../../utils/getComponentLocalNames'\nimport {getStaticAttributeExpression} from '../../../utils/getStaticAttributeExpression'\nimport {getStyledComponentAliases} from '../../../utils/getStyledComponentAliases'\nimport {replaceElement} from '../../../utils/replaceElement'\nimport {shouldTransformComponent} from '../../../utils/shouldTransformComponent'\nimport {transformAttributes} from '../../../utils/transformAttributes'\nimport {transformComponent} from '../../../utils/transformComponent'\nimport {transformImport} from '../../../utils/transformImport'\nimport {transformStyledComponents} from '../../../utils/transformStyledComponents'\nimport {FLEX_MODS} from '../flex/flex.mods'\nimport {GRID_MODS} from '../grid/grid.mods'\nimport {BOX_MODS} from './box.mods'\n\nconst BOX_TODO_WARNING = 'Please double check the Box migration below'\nconst FLEX_TODO_WARNING = 'Please double check the Flex migration below'\nconst GRID_TODO_WARNING = 'Please double check the Grid migration below'\nconst STYLED_TODO_WARNING = 'Please double check styled(Box) migration below'\n\n/** @internal */\nexport default function transform(\n fileInfo: FileInfo,\n api: API,\n options?: BaseOptions,\n): string | undefined {\n const {fromPackage, toPackage} = options || {}\n\n return transformComponent(fileInfo, api, ({j, root, markChanged}) => {\n const localNames = getComponentLocalNames(j, root, 'Box', options)\n const styledAliases = getStyledComponentAliases(\n j,\n root,\n 'Box',\n fileInfo.path,\n localNames,\n options,\n )\n\n if (!shouldTransformComponent(j, root, 'Box', localNames, options, styledAliases)) {\n return\n }\n\n const matchesDisplayValue = (\n attrs: (JSXAttribute | JSXSpreadAttribute)[],\n suffix: string,\n exclude: string[],\n ) => {\n const display = getStaticAttributeExpression(j, attrs, 'display') || []\n const values = Array.isArray(display) ? display : [display]\n let matchesExclude\n\n for (const excluded of exclude) {\n if (values.some((value) => typeof value === 'string' && value.endsWith(excluded))) {\n matchesExclude = true\n break\n }\n }\n\n if (matchesExclude) {\n return false\n }\n\n return values.some((value) => typeof value === 'string' && value.endsWith(suffix))\n }\n\n const replaceWithFlex = (attrs: (JSXAttribute | JSXSpreadAttribute)[]) =>\n matchesDisplayValue(attrs, 'flex', ['block', 'inline', 'grid'])\n\n const replaceWithGrid = (attrs: (JSXAttribute | JSXSpreadAttribute)[]) =>\n matchesDisplayValue(attrs, 'grid', ['block', 'inline', 'flex'])\n\n if (transformImport(j, root, 'Box', fromPackage, toPackage)) {\n markChanged()\n }\n\n if (\n replaceElement(\n j,\n root,\n replaceWithFlex,\n {\n element: 'Box',\n localNames,\n },\n {\n element: 'Flex',\n callback: (path) => transformAttributes(j, path, FLEX_MODS, FLEX_TODO_WARNING),\n },\n )\n ) {\n markChanged()\n }\n\n if (\n replaceElement(\n j,\n root,\n replaceWithGrid,\n {\n element: 'Box',\n localNames,\n callback: (path) => transformAttributes(j, path, BOX_MODS, BOX_TODO_WARNING),\n },\n {\n element: 'Grid',\n callback: (path) => transformAttributes(j, path, GRID_MODS, GRID_TODO_WARNING),\n },\n )\n ) {\n markChanged()\n }\n\n if (\n transformStyledComponents(\n j,\n root,\n styledAliases,\n (attrs) => !replaceWithFlex(attrs) && !replaceWithGrid(attrs),\n {\n warning: STYLED_TODO_WARNING,\n callback: (path) => transformAttributes(j, path, BOX_MODS, BOX_TODO_WARNING),\n },\n )\n ) {\n markChanged()\n }\n })\n}\n"],"names":[],"mappings":";;;;;AAgBA,MAAM,mBAAmB,+CACnB,oBAAoB,gDACpB,oBAAoB,gDACpB,sBAAsB;AAG5B,SAAwB,UACtB,UACA,KACA,SACoB;AACpB,QAAM,EAAC,aAAa,UAAA,IAAa,WAAW,CAAA;AAE5C,SAAO,mBAAmB,UAAU,KAAK,CAAC,EAAC,GAAG,MAAM,kBAAiB;AACnE,UAAM,aAAa,uBAAuB,GAAG,MAAM,OAAO,OAAO,GAC3D,gBAAgB;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA;AAAA,IAAA;AAGF,QAAI,CAAC,yBAAyB,GAAG,MAAM,OAAO,YAAY,SAAS,aAAa;AAC9E;AAGF,UAAM,sBAAsB,CAC1B,OACA,QACA,YACG;AACH,YAAM,UAAU,6BAA6B,GAAG,OAAO,SAAS,KAAK,CAAA,GAC/D,SAAS,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC,OAAO;AAC1D,UAAI;AAEJ,iBAAW,YAAY;AACrB,YAAI,OAAO,KAAK,CAAC,UAAU,OAAO,SAAU,YAAY,MAAM,SAAS,QAAQ,CAAC,GAAG;AACjF,2BAAiB;AACjB;AAAA,QACF;AAGF,aAAI,iBACK,KAGF,OAAO,KAAK,CAAC,UAAU,OAAO,SAAU,YAAY,MAAM,SAAS,MAAM,CAAC;AAAA,IACnF,GAEM,kBAAkB,CAAC,UACvB,oBAAoB,OAAO,QAAQ,CAAC,SAAS,UAAU,MAAM,CAAC,GAE1D,kBAAkB,CAAC,UACvB,oBAAoB,OAAO,QAAQ,CAAC,SAAS,UAAU,MAAM,CAAC;AAE5D,oBAAgB,GAAG,MAAM,OAAO,aAAa,SAAS,KACxD,eAIA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,QACE,SAAS;AAAA,QACT;AAAA,MAAA;AAAA,MAEF;AAAA,QACE,SAAS;AAAA,QACT,UAAU,CAAC,SAAS,oBAAoB,GAAG,MAAM,WAAW,iBAAiB;AAAA,MAAA;AAAA,IAC/E,KAGF,eAIA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,QACE,SAAS;AAAA,QACT;AAAA,QACA,UAAU,CAAC,SAAS,oBAAoB,GAAG,MAAM,UAAU,gBAAgB;AAAA,MAAA;AAAA,MAE7E;AAAA,QACE,SAAS;AAAA,QACT,UAAU,CAAC,SAAS,oBAAoB,GAAG,MAAM,WAAW,iBAAiB;AAAA,MAAA;AAAA,IAC/E,KAGF,eAIA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA,CAAC,UAAU,CAAC,gBAAgB,KAAK,KAAK,CAAC,gBAAgB,KAAK;AAAA,MAC5D;AAAA,QACE,SAAS;AAAA,QACT,UAAU,CAAC,SAAS,oBAAoB,GAAG,MAAM,UAAU,gBAAgB;AAAA,MAAA;AAAA,IAC7E,KAGF,YAAA;AAAA,EAEJ,CAAC;AACH;"}
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import "jscodeshift";
|
|
2
2
|
import { transformComponent, getComponentLocalNames, shouldTransformComponent, transformImport, transformAttributes } from "../../../_chunks-es/transformComponent.js";
|
|
3
|
-
import { FLEX_MODS } from "../../../_chunks-es/flex.mods.js";
|
|
3
|
+
import { getStyledComponentAliases, transformStyledComponents, FLEX_MODS } from "../../../_chunks-es/flex.mods.js";
|
|
4
4
|
const TODO_WARNING = "Please double check the Flex migration below";
|
|
5
5
|
function transform(fileInfo, api, options) {
|
|
6
6
|
const { fromPackage, toPackage } = options || {};
|
|
7
7
|
return transformComponent(fileInfo, api, ({ j, root, markChanged }) => {
|
|
8
|
-
const localNames = getComponentLocalNames(j, root, "Flex", options)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
const localNames = getComponentLocalNames(j, root, "Flex", options), styledAliases = getStyledComponentAliases(
|
|
9
|
+
j,
|
|
10
|
+
root,
|
|
11
|
+
"Flex",
|
|
12
|
+
fileInfo.path,
|
|
13
|
+
localNames,
|
|
14
|
+
options
|
|
15
|
+
);
|
|
16
|
+
shouldTransformComponent(j, root, "Flex", localNames, options, styledAliases) && (transformImport(j, root, "Flex", fromPackage, toPackage) && markChanged(), root.find(j.JSXOpeningElement).forEach((path) => {
|
|
17
|
+
const name = path.node.name;
|
|
18
|
+
name.type !== "JSXIdentifier" || !localNames.has(name.name) || transformAttributes(j, path, FLEX_MODS, TODO_WARNING) && markChanged();
|
|
19
|
+
}), transformStyledComponents(j, root, styledAliases, () => !0, {
|
|
20
|
+
callback: (path) => transformAttributes(j, path, FLEX_MODS, TODO_WARNING)
|
|
21
|
+
}) && markChanged());
|
|
14
22
|
});
|
|
15
23
|
}
|
|
16
24
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flex.js","sources":["../../../../src/transforms/latest/flex/flex.ts"],"sourcesContent":["import {type API, type FileInfo} from 'jscodeshift'\n\nimport type {BaseOptions} from '../../../types/BaseOptions'\nimport {getComponentLocalNames} from '../../../utils/getComponentLocalNames'\nimport {shouldTransformComponent} from '../../../utils/shouldTransformComponent'\nimport {transformAttributes} from '../../../utils/transformAttributes'\nimport {transformComponent} from '../../../utils/transformComponent'\nimport {transformImport} from '../../../utils/transformImport'\nimport {FLEX_MODS} from './flex.mods'\n\nconst TODO_WARNING = 'Please double check the Flex migration below'\n\n/** @internal */\nexport default function transform(\n fileInfo: FileInfo,\n api: API,\n options: BaseOptions,\n): string | undefined {\n const {fromPackage, toPackage} = options || {}\n\n return transformComponent(fileInfo, api, ({j, root, markChanged}) => {\n const localNames = getComponentLocalNames(j, root, 'Flex', options)\n\n if (!shouldTransformComponent(j, root, 'Flex', localNames, options)) {\n return\n }\n\n if (transformImport(j, root, 'Flex', fromPackage, toPackage)) {\n markChanged()\n }\n\n root
|
|
1
|
+
{"version":3,"file":"flex.js","sources":["../../../../src/transforms/latest/flex/flex.ts"],"sourcesContent":["import {type API, type FileInfo} from 'jscodeshift'\n\nimport type {BaseOptions} from '../../../types/BaseOptions'\nimport {getComponentLocalNames} from '../../../utils/getComponentLocalNames'\nimport {getStyledComponentAliases} from '../../../utils/getStyledComponentAliases'\nimport {shouldTransformComponent} from '../../../utils/shouldTransformComponent'\nimport {transformAttributes} from '../../../utils/transformAttributes'\nimport {transformComponent} from '../../../utils/transformComponent'\nimport {transformImport} from '../../../utils/transformImport'\nimport {transformStyledComponents} from '../../../utils/transformStyledComponents'\nimport {FLEX_MODS} from './flex.mods'\n\nconst TODO_WARNING = 'Please double check the Flex migration below'\n\n/** @internal */\nexport default function transform(\n fileInfo: FileInfo,\n api: API,\n options: BaseOptions,\n): string | undefined {\n const {fromPackage, toPackage} = options || {}\n\n return transformComponent(fileInfo, api, ({j, root, markChanged}) => {\n const localNames = getComponentLocalNames(j, root, 'Flex', options)\n const styledAliases = getStyledComponentAliases(\n j,\n root,\n 'Flex',\n fileInfo.path,\n localNames,\n options,\n )\n\n if (!shouldTransformComponent(j, root, 'Flex', localNames, options, styledAliases)) {\n return\n }\n\n if (transformImport(j, root, 'Flex', fromPackage, toPackage)) {\n markChanged()\n }\n\n root.find(j.JSXOpeningElement).forEach((path) => {\n const name = path.node.name\n\n if (name.type !== 'JSXIdentifier' || !localNames.has(name.name)) {\n return\n }\n\n if (transformAttributes(j, path, FLEX_MODS, TODO_WARNING)) {\n markChanged()\n }\n })\n\n if (\n transformStyledComponents(j, root, styledAliases, () => true, {\n callback: (path) => transformAttributes(j, path, FLEX_MODS, TODO_WARNING),\n })\n ) {\n markChanged()\n }\n })\n}\n"],"names":[],"mappings":";;;AAYA,MAAM,eAAe;AAGrB,SAAwB,UACtB,UACA,KACA,SACoB;AACpB,QAAM,EAAC,aAAa,UAAA,IAAa,WAAW,CAAA;AAE5C,SAAO,mBAAmB,UAAU,KAAK,CAAC,EAAC,GAAG,MAAM,kBAAiB;AACnE,UAAM,aAAa,uBAAuB,GAAG,MAAM,QAAQ,OAAO,GAC5D,gBAAgB;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA;AAAA,IAAA;AAGG,6BAAyB,GAAG,MAAM,QAAQ,YAAY,SAAS,aAAa,MAI7E,gBAAgB,GAAG,MAAM,QAAQ,aAAa,SAAS,KACzD,YAAA,GAGF,KAAK,KAAK,EAAE,iBAAiB,EAAE,QAAQ,CAAC,SAAS;AAC/C,YAAM,OAAO,KAAK,KAAK;AAEnB,WAAK,SAAS,mBAAmB,CAAC,WAAW,IAAI,KAAK,IAAI,KAI1D,oBAAoB,GAAG,MAAM,WAAW,YAAY,KACtD,YAAA;AAAA,IAEJ,CAAC,GAGC,0BAA0B,GAAG,MAAM,eAAe,MAAM,IAAM;AAAA,MAC5D,UAAU,CAAC,SAAS,oBAAoB,GAAG,MAAM,WAAW,YAAY;AAAA,IAAA,CACzE,KAED,YAAA;AAAA,EAEJ,CAAC;AACH;"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {tmpdir} from 'node:os'
|
|
3
|
-
import {join} from 'node:path'
|
|
1
|
+
import {expect} from 'vitest'
|
|
4
2
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
const applyTransform = require('jscodeshift/dist/testUtils').applyTransform
|
|
8
|
-
|
|
9
|
-
import {clearModuleParseCache} from '../../../utils/parseModule'
|
|
10
|
-
import {defineInlineTest} from '../../../utils/testUtils'
|
|
3
|
+
import {defineCrossFileTest, defineInlineTest} from '../../../utils/testUtils'
|
|
11
4
|
import transform from './box'
|
|
12
5
|
|
|
13
6
|
defineInlineTest(
|
|
@@ -246,157 +239,104 @@ defineInlineTest(
|
|
|
246
239
|
'warns and does not transform attributes if styled Box should be replaced',
|
|
247
240
|
)
|
|
248
241
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
for (const dir of tempDirs.splice(0)) {
|
|
255
|
-
rmSync(dir, {recursive: true, force: true})
|
|
256
|
-
}
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
describe('cross-file styled aliases', () => {
|
|
260
|
-
it('transforms attributes on imported styled Box wrappers', () => {
|
|
261
|
-
const dir = mkdtempSync(join(tmpdir(), 'ui-codemod-box-crossfile-'))
|
|
262
|
-
|
|
263
|
-
tempDirs.push(dir)
|
|
264
|
-
|
|
265
|
-
writeFileSync(
|
|
266
|
-
join(dir, 'Component.styled.tsx'),
|
|
267
|
-
`
|
|
268
|
-
import {Box} from '@sanity/ui'
|
|
269
|
-
|
|
270
|
-
export const RootBox = styled(Box)(({theme}) => ({}))
|
|
271
|
-
`,
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
writeFileSync(
|
|
275
|
-
join(dir, 'Component.tsx'),
|
|
276
|
-
`
|
|
277
|
-
import {RootBox} from './Component.styled'
|
|
278
|
-
|
|
279
|
-
export function Component() {
|
|
280
|
-
return <RootBox alignItems="center" />
|
|
281
|
-
}
|
|
282
|
-
`,
|
|
283
|
-
)
|
|
242
|
+
defineCrossFileTest(
|
|
243
|
+
transform,
|
|
244
|
+
{},
|
|
245
|
+
`
|
|
246
|
+
import {Box} from '@sanity/ui'
|
|
284
247
|
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
248
|
+
export const RootBox = styled(Box)(({theme}) => ({}))
|
|
249
|
+
`,
|
|
250
|
+
`
|
|
251
|
+
import {RootBox} from './Component.styled'
|
|
288
252
|
|
|
253
|
+
export function Component() {
|
|
254
|
+
return <RootBox alignItems="center" />
|
|
255
|
+
}
|
|
256
|
+
`,
|
|
257
|
+
(output) => {
|
|
289
258
|
expect(output).toContain('alignItems: "center"')
|
|
290
259
|
expect(output).not.toContain('<RootBox alignItems="center" />')
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const dir = mkdtempSync(join(tmpdir(), 'ui-codemod-box-crossfile-todo-'))
|
|
295
|
-
|
|
296
|
-
tempDirs.push(dir)
|
|
297
|
-
|
|
298
|
-
writeFileSync(
|
|
299
|
-
join(dir, 'Component.styled.tsx'),
|
|
300
|
-
`
|
|
301
|
-
import {Box} from '@sanity/ui'
|
|
302
|
-
|
|
303
|
-
export const RootBox = styled(Box)(({theme}) => ({}))
|
|
304
|
-
`,
|
|
305
|
-
)
|
|
306
|
-
|
|
307
|
-
writeFileSync(
|
|
308
|
-
join(dir, 'Component.tsx'),
|
|
309
|
-
`
|
|
310
|
-
import {RootBox} from './Component.styled'
|
|
260
|
+
},
|
|
261
|
+
'transforms attributes on imported styled Box wrappers',
|
|
262
|
+
)
|
|
311
263
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
264
|
+
defineCrossFileTest(
|
|
265
|
+
transform,
|
|
266
|
+
{},
|
|
267
|
+
`
|
|
268
|
+
import {Box} from '@sanity/ui'
|
|
317
269
|
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
|
|
270
|
+
export const RootBox = styled(Box)(({theme}) => ({}))
|
|
271
|
+
`,
|
|
272
|
+
`
|
|
273
|
+
import {RootBox} from './Component.styled'
|
|
321
274
|
|
|
275
|
+
export function Component() {
|
|
276
|
+
return <RootBox display="flex" alignItems="center" />
|
|
277
|
+
}
|
|
278
|
+
`,
|
|
279
|
+
(output) => {
|
|
322
280
|
expect(output).toContain('UI-CODEMOD TODO: Please double check styled(Box) migration below')
|
|
323
281
|
expect(output).toContain('<RootBox display="flex" alignItems="center" />')
|
|
324
282
|
expect(output).not.toContain('const RootBox = styled(Box)')
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const dir = mkdtempSync(join(tmpdir(), 'ui-codemod-box-crossfile-unrelated-'))
|
|
329
|
-
|
|
330
|
-
tempDirs.push(dir)
|
|
331
|
-
|
|
332
|
-
writeFileSync(
|
|
333
|
-
join(dir, 'Component.styled.tsx'),
|
|
334
|
-
`
|
|
335
|
-
import {Box} from '@sanity/ui'
|
|
336
|
-
|
|
337
|
-
export const RootBox = styled(Box)(({theme}) => ({}))
|
|
338
|
-
`,
|
|
339
|
-
)
|
|
340
|
-
|
|
341
|
-
writeFileSync(
|
|
342
|
-
join(dir, 'Component.tsx'),
|
|
343
|
-
`
|
|
344
|
-
import {Box} from 'another-package'
|
|
345
|
-
import {RootBox} from './Component.styled'
|
|
346
|
-
|
|
347
|
-
export function Component() {
|
|
348
|
-
return (
|
|
349
|
-
<>
|
|
350
|
-
<RootBox alignItems="center" />
|
|
351
|
-
<Box display="flex" />
|
|
352
|
-
</>
|
|
353
|
-
)
|
|
354
|
-
}
|
|
355
|
-
`,
|
|
356
|
-
)
|
|
357
|
-
|
|
358
|
-
const importerPath = join(dir, 'Component.tsx')
|
|
359
|
-
const source = readFileSync(importerPath, 'utf8')
|
|
360
|
-
const output = applyTransform(transform, {}, {source, path: importerPath}, {parser: 'tsx'})
|
|
283
|
+
},
|
|
284
|
+
'adds todo warning when imported styled Box wrapper should be replaced',
|
|
285
|
+
)
|
|
361
286
|
|
|
287
|
+
defineCrossFileTest(
|
|
288
|
+
transform,
|
|
289
|
+
{},
|
|
290
|
+
`
|
|
291
|
+
import {Box} from '@sanity/ui'
|
|
292
|
+
|
|
293
|
+
export const RootBox = styled(Box)(({theme}) => ({}))
|
|
294
|
+
`,
|
|
295
|
+
`
|
|
296
|
+
import {Box} from 'another-package'
|
|
297
|
+
import {RootBox} from './Component.styled'
|
|
298
|
+
|
|
299
|
+
export function Component() {
|
|
300
|
+
return (
|
|
301
|
+
<>
|
|
302
|
+
<RootBox alignItems="center" />
|
|
303
|
+
<Box display="flex" />
|
|
304
|
+
</>
|
|
305
|
+
)
|
|
306
|
+
}
|
|
307
|
+
`,
|
|
308
|
+
(output) => {
|
|
362
309
|
expect(output).toContain('alignItems: "center"')
|
|
363
310
|
expect(output).not.toContain('<RootBox alignItems="center" />')
|
|
364
311
|
expect(output).toContain('<Box display="flex" />')
|
|
365
312
|
expect(output).not.toContain('<Flex')
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
const dir = mkdtempSync(join(tmpdir(), 'ui-codemod-box-crossfile-barrel-'))
|
|
370
|
-
|
|
371
|
-
tempDirs.push(dir)
|
|
372
|
-
|
|
373
|
-
writeFileSync(
|
|
374
|
-
join(dir, 'Component.styled.tsx'),
|
|
375
|
-
`
|
|
376
|
-
import {Box} from '@sanity/ui'
|
|
377
|
-
|
|
378
|
-
export const RootBox = styled(Box)(({theme}) => ({}))
|
|
379
|
-
`,
|
|
380
|
-
)
|
|
381
|
-
|
|
382
|
-
writeFileSync(join(dir, 'index.ts'), `export {RootBox} from './Component.styled'`)
|
|
383
|
-
|
|
384
|
-
writeFileSync(
|
|
385
|
-
join(dir, 'Component.tsx'),
|
|
386
|
-
`
|
|
387
|
-
import {RootBox} from './index'
|
|
313
|
+
},
|
|
314
|
+
'does not rewrite unrelated Box from another package',
|
|
315
|
+
)
|
|
388
316
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
317
|
+
defineCrossFileTest(
|
|
318
|
+
transform,
|
|
319
|
+
{},
|
|
320
|
+
`
|
|
321
|
+
import {Box} from '@sanity/ui'
|
|
394
322
|
|
|
395
|
-
const
|
|
396
|
-
|
|
397
|
-
|
|
323
|
+
export const RootBox = styled(Box)(({theme}) => ({}))
|
|
324
|
+
`,
|
|
325
|
+
`
|
|
326
|
+
import {RootBox} from './index'
|
|
398
327
|
|
|
328
|
+
export function Component() {
|
|
329
|
+
return <RootBox alignItems="center" />
|
|
330
|
+
}
|
|
331
|
+
`,
|
|
332
|
+
(output) => {
|
|
399
333
|
expect(output).toContain('alignItems: "center"')
|
|
400
334
|
expect(output).not.toContain('<RootBox alignItems="center" />')
|
|
401
|
-
}
|
|
402
|
-
|
|
335
|
+
},
|
|
336
|
+
'transforms styled Box wrappers imported through barrel re-exports',
|
|
337
|
+
{
|
|
338
|
+
extraFiles: {
|
|
339
|
+
'index.ts': `export {RootBox} from './Component.styled'`,
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
)
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {expect} from 'vitest'
|
|
2
|
+
|
|
3
|
+
import {defineCrossFileTest, defineInlineTest} from '../../../utils/testUtils'
|
|
2
4
|
import transform from './flex'
|
|
3
5
|
|
|
4
6
|
defineInlineTest(
|
|
@@ -78,3 +80,78 @@ defineInlineTest(
|
|
|
78
80
|
`,
|
|
79
81
|
'moves grid props to style and updates mapped values',
|
|
80
82
|
)
|
|
83
|
+
|
|
84
|
+
defineCrossFileTest(
|
|
85
|
+
transform,
|
|
86
|
+
{},
|
|
87
|
+
`
|
|
88
|
+
import {Flex} from '@sanity/ui'
|
|
89
|
+
|
|
90
|
+
export const RootFlex = styled(Flex)(({theme}) => ({}))
|
|
91
|
+
`,
|
|
92
|
+
`
|
|
93
|
+
import {RootFlex} from './Component.styled'
|
|
94
|
+
|
|
95
|
+
export function Component() {
|
|
96
|
+
return <RootFlex align="center" />
|
|
97
|
+
}
|
|
98
|
+
`,
|
|
99
|
+
(output) => {
|
|
100
|
+
expect(output).toContain('<RootFlex alignItems="center" />')
|
|
101
|
+
},
|
|
102
|
+
'transforms attributes on imported styled Flex wrappers',
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
defineCrossFileTest(
|
|
106
|
+
transform,
|
|
107
|
+
{},
|
|
108
|
+
`
|
|
109
|
+
import {Flex} from '@sanity/ui'
|
|
110
|
+
|
|
111
|
+
export const RootFlex = styled(Flex)(({theme}) => ({}))
|
|
112
|
+
`,
|
|
113
|
+
`
|
|
114
|
+
import {Flex} from 'another-package'
|
|
115
|
+
import {RootFlex} from './Component.styled'
|
|
116
|
+
|
|
117
|
+
export function Component() {
|
|
118
|
+
return (
|
|
119
|
+
<>
|
|
120
|
+
<RootFlex align="center" />
|
|
121
|
+
<Flex direction="column" />
|
|
122
|
+
</>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
`,
|
|
126
|
+
(output) => {
|
|
127
|
+
expect(output).toContain('<RootFlex alignItems="center" />')
|
|
128
|
+
expect(output).toContain('<Flex direction="column" />')
|
|
129
|
+
},
|
|
130
|
+
'does not transform attributes on unrelated Flex from another package',
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
defineCrossFileTest(
|
|
134
|
+
transform,
|
|
135
|
+
{},
|
|
136
|
+
`
|
|
137
|
+
import {Flex} from '@sanity/ui'
|
|
138
|
+
|
|
139
|
+
export const RootFlex = styled(Flex)(({theme}) => ({}))
|
|
140
|
+
`,
|
|
141
|
+
`
|
|
142
|
+
import {RootFlex} from './index'
|
|
143
|
+
|
|
144
|
+
export function Component() {
|
|
145
|
+
return <RootFlex align="center" />
|
|
146
|
+
}
|
|
147
|
+
`,
|
|
148
|
+
(output) => {
|
|
149
|
+
expect(output).toContain('<RootFlex alignItems="center" />')
|
|
150
|
+
},
|
|
151
|
+
'transforms styled Flex wrappers imported through barrel re-exports',
|
|
152
|
+
{
|
|
153
|
+
extraFiles: {
|
|
154
|
+
'index.ts': `export {RootFlex} from './Component.styled'`,
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
)
|
|
@@ -2,10 +2,12 @@ import {type API, type FileInfo} from 'jscodeshift'
|
|
|
2
2
|
|
|
3
3
|
import type {BaseOptions} from '../../../types/BaseOptions'
|
|
4
4
|
import {getComponentLocalNames} from '../../../utils/getComponentLocalNames'
|
|
5
|
+
import {getStyledComponentAliases} from '../../../utils/getStyledComponentAliases'
|
|
5
6
|
import {shouldTransformComponent} from '../../../utils/shouldTransformComponent'
|
|
6
7
|
import {transformAttributes} from '../../../utils/transformAttributes'
|
|
7
8
|
import {transformComponent} from '../../../utils/transformComponent'
|
|
8
9
|
import {transformImport} from '../../../utils/transformImport'
|
|
10
|
+
import {transformStyledComponents} from '../../../utils/transformStyledComponents'
|
|
9
11
|
import {FLEX_MODS} from './flex.mods'
|
|
10
12
|
|
|
11
13
|
const TODO_WARNING = 'Please double check the Flex migration below'
|
|
@@ -20,8 +22,16 @@ export default function transform(
|
|
|
20
22
|
|
|
21
23
|
return transformComponent(fileInfo, api, ({j, root, markChanged}) => {
|
|
22
24
|
const localNames = getComponentLocalNames(j, root, 'Flex', options)
|
|
25
|
+
const styledAliases = getStyledComponentAliases(
|
|
26
|
+
j,
|
|
27
|
+
root,
|
|
28
|
+
'Flex',
|
|
29
|
+
fileInfo.path,
|
|
30
|
+
localNames,
|
|
31
|
+
options,
|
|
32
|
+
)
|
|
23
33
|
|
|
24
|
-
if (!shouldTransformComponent(j, root, 'Flex', localNames, options)) {
|
|
34
|
+
if (!shouldTransformComponent(j, root, 'Flex', localNames, options, styledAliases)) {
|
|
25
35
|
return
|
|
26
36
|
}
|
|
27
37
|
|
|
@@ -29,14 +39,24 @@ export default function transform(
|
|
|
29
39
|
markChanged()
|
|
30
40
|
}
|
|
31
41
|
|
|
32
|
-
root
|
|
33
|
-
.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
root.find(j.JSXOpeningElement).forEach((path) => {
|
|
43
|
+
const name = path.node.name
|
|
44
|
+
|
|
45
|
+
if (name.type !== 'JSXIdentifier' || !localNames.has(name.name)) {
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (transformAttributes(j, path, FLEX_MODS, TODO_WARNING)) {
|
|
50
|
+
markChanged()
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
if (
|
|
55
|
+
transformStyledComponents(j, root, styledAliases, () => true, {
|
|
56
|
+
callback: (path) => transformAttributes(j, path, FLEX_MODS, TODO_WARNING),
|
|
40
57
|
})
|
|
58
|
+
) {
|
|
59
|
+
markChanged()
|
|
60
|
+
}
|
|
41
61
|
})
|
|
42
62
|
}
|
package/src/utils/testUtils.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import {mkdtempSync, readFileSync, rmSync, writeFileSync} from 'node:fs'
|
|
2
|
+
import {tmpdir} from 'node:os'
|
|
3
|
+
import {join} from 'node:path'
|
|
4
|
+
|
|
1
5
|
import {type FileInfo, type Options, type Transform} from 'jscodeshift'
|
|
2
6
|
import {expect, it} from 'vitest'
|
|
3
7
|
|
|
8
|
+
import {clearModuleParseCache} from './parseModule'
|
|
9
|
+
|
|
4
10
|
const applyTransform = require('jscodeshift/dist/testUtils').applyTransform
|
|
5
11
|
|
|
6
12
|
export function defineInlineTest(
|
|
@@ -52,3 +58,42 @@ function runInlineTest(
|
|
|
52
58
|
expectation(output)
|
|
53
59
|
return output
|
|
54
60
|
}
|
|
61
|
+
|
|
62
|
+
export function defineCrossFileTest(
|
|
63
|
+
module: Transform,
|
|
64
|
+
options: Options,
|
|
65
|
+
styledInput: string,
|
|
66
|
+
importerInput: string,
|
|
67
|
+
assert: (output: string) => void,
|
|
68
|
+
testName?: string,
|
|
69
|
+
crossFileOptions?: {
|
|
70
|
+
extraFiles?: Record<string, string>
|
|
71
|
+
},
|
|
72
|
+
) {
|
|
73
|
+
it(testName || 'transforms cross-file styled component correctly', async () => {
|
|
74
|
+
const dir = mkdtempSync(join(tmpdir(), 'ui-codemod-crossfile-'))
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
writeFileSync(join(dir, 'Component.styled.tsx'), styledInput.trim())
|
|
78
|
+
writeFileSync(join(dir, 'Component.tsx'), importerInput.trim())
|
|
79
|
+
|
|
80
|
+
for (const [filePath, source] of Object.entries(crossFileOptions?.extraFiles ?? {})) {
|
|
81
|
+
writeFileSync(join(dir, filePath), source.trim())
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const importerPath = join(dir, 'Component.tsx')
|
|
85
|
+
const source = readFileSync(importerPath, 'utf8')
|
|
86
|
+
const output = await applyTransform(
|
|
87
|
+
module,
|
|
88
|
+
options,
|
|
89
|
+
{source, path: importerPath},
|
|
90
|
+
{parser: 'tsx'},
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
assert(typeof output === 'string' ? output : '')
|
|
94
|
+
} finally {
|
|
95
|
+
clearModuleParseCache()
|
|
96
|
+
rmSync(dir, {recursive: true, force: true})
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
}
|