-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
update-react-dom-render-for-v18.ts
104 lines (94 loc) · 2.5 KB
/
update-react-dom-render-for-v18.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import {
applyChangesToString,
ChangeType,
getProjects,
StringChange,
stripIndents,
Tree,
formatFiles,
} from '@nrwl/devkit';
import { findNodes } from 'nx/src/utils/typescript';
import * as ts from 'typescript';
export async function update(tree: Tree) {
const projects = getProjects(tree);
projects.forEach((config, name) => {
const isReactProject =
config.targets?.build?.executor === '@nrwl/web:webpack' &&
/main\.(t|j)sx?$/.test(config.targets.build.options.main);
if (isReactProject) {
const sourcePath = config.targets.build.options.main;
const sourceCode = tree.read(sourcePath).toString();
const source = ts.createSourceFile(
sourcePath,
sourceCode,
ts.ScriptTarget.Latest,
true
);
const result = applyChangesToString(
sourceCode,
migrateReactDomRender(sourcePath, source)
);
tree.write(sourcePath, result);
}
});
await formatFiles(tree);
}
export function migrateReactDomRender(
sourcePath: string,
source: ts.SourceFile
): StringChange[] {
const allImports = findNodes(
source,
ts.SyntaxKind.ImportDeclaration
) as ts.ImportDeclaration[];
const reactDomImport = allImports.find(
(x) => x.moduleSpecifier.getText() === "'react-dom'"
);
const changes = [] as StringChange[];
if (reactDomImport) {
changes.push({
type: ChangeType.Insert,
index: reactDomImport.moduleSpecifier.end - 1,
text: '/client',
});
}
const calls = findNodes(
source,
ts.SyntaxKind.CallExpression
) as ts.CallExpression[];
const renderCall = calls.find((x) => {
if (x.expression.kind !== ts.SyntaxKind.PropertyAccessExpression)
return false;
const expr = x.expression as ts.PropertyAccessExpression;
return (
expr.expression.getText() === 'ReactDOM' &&
expr.name.getText() === 'render'
);
});
if (renderCall) {
const [element, querySelector] = renderCall.arguments;
changes.push(
{
type: ChangeType.Delete,
start: renderCall.getStart(),
length: renderCall.end,
},
{
type: ChangeType.Insert,
index: renderCall.getStart(),
text: stripIndents`
const root = ReactDOM.createRoot(
${querySelector.getText()}${
sourcePath.endsWith('.tsx') ? ' as HTMLElement' : ''
}
);
root.render(
${element.getText()}
);
`,
}
);
}
return changes;
}
export default update;