@payloadcms/codemod 4.0.0-internal.44ac9c8 → 4.0.0-internal.4a6b4c3
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/README.md +6 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.help.d.ts +4 -0
- package/dist/cli.help.d.ts.map +1 -0
- package/dist/cli.help.js +29 -0
- package/dist/cli.help.js.map +1 -0
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -1
- package/dist/cli.parseFlags.d.ts +1 -0
- package/dist/cli.parseFlags.d.ts.map +1 -1
- package/dist/cli.parseFlags.js +6 -0
- package/dist/cli.parseFlags.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +6 -0
- package/dist/registry.js.map +1 -1
- package/dist/runbook/payload-v4-upgrade.md +2 -2
- package/dist/runbook/v4.mdx +370 -80
- package/dist/transforms/migrate-admin-context-properties/basic.input.js +32 -0
- package/dist/transforms/migrate-admin-context-properties/basic.input.js.map +1 -0
- package/dist/transforms/migrate-admin-context-properties/basic.output.js +30 -0
- package/dist/transforms/migrate-admin-context-properties/basic.output.js.map +1 -0
- package/dist/transforms/migrate-admin-context-properties/index.d.ts +3 -0
- package/dist/transforms/migrate-admin-context-properties/index.d.ts.map +1 -0
- package/dist/transforms/migrate-admin-context-properties/index.js +302 -0
- package/dist/transforms/migrate-admin-context-properties/index.js.map +1 -0
- package/dist/transforms/migrate-admin-context-properties/no-match.input.js +30 -0
- package/dist/transforms/migrate-admin-context-properties/no-match.input.js.map +1 -0
- package/dist/transforms/migrate-admin-context-properties/no-match.output.js +30 -0
- package/dist/transforms/migrate-admin-context-properties/no-match.output.js.map +1 -0
- package/dist/transforms/migrate-displayed-field-value-args/basic.input.js +4 -0
- package/dist/transforms/migrate-displayed-field-value-args/basic.input.js.map +1 -0
- package/dist/transforms/migrate-displayed-field-value-args/basic.output.js +8 -0
- package/dist/transforms/migrate-displayed-field-value-args/basic.output.js.map +1 -0
- package/dist/transforms/migrate-displayed-field-value-args/index.d.ts +3 -0
- package/dist/transforms/migrate-displayed-field-value-args/index.d.ts.map +1 -0
- package/dist/transforms/migrate-displayed-field-value-args/index.js +84 -0
- package/dist/transforms/migrate-displayed-field-value-args/index.js.map +1 -0
- package/dist/transforms/migrate-displayed-field-value-args/namespace.input.js +4 -0
- package/dist/transforms/migrate-displayed-field-value-args/namespace.input.js.map +1 -0
- package/dist/transforms/migrate-displayed-field-value-args/namespace.output.js +8 -0
- package/dist/transforms/migrate-displayed-field-value-args/namespace.output.js.map +1 -0
- package/dist/transforms/migrate-displayed-field-value-args/no-match.input.js +4 -0
- package/dist/transforms/migrate-displayed-field-value-args/no-match.input.js.map +1 -0
- package/dist/transforms/migrate-displayed-field-value-args/no-match.output.js +4 -0
- package/dist/transforms/migrate-displayed-field-value-args/no-match.output.js.map +1 -0
- package/dist/transforms/migrate-field-component-types/index.d.ts.map +1 -1
- package/dist/transforms/migrate-field-component-types/index.js +4 -0
- package/dist/transforms/migrate-field-component-types/index.js.map +1 -1
- package/dist/transforms/migrate-sharp-to-transformer/basic.output.js +1 -1
- package/dist/transforms/migrate-sharp-to-transformer/basic.output.js.map +1 -1
- package/dist/transforms/migrate-sharp-to-transformer/existing-transformers.output.js +1 -1
- package/dist/transforms/migrate-sharp-to-transformer/existing-transformers.output.js.map +1 -1
- package/dist/transforms/migrate-sharp-to-transformer/index.d.ts.map +1 -1
- package/dist/transforms/migrate-sharp-to-transformer/index.js +232 -82
- package/dist/transforms/migrate-sharp-to-transformer/index.js.map +1 -1
- package/dist/transforms/remove-storage-always-insert-fields/index.d.ts.map +1 -1
- package/dist/transforms/remove-storage-always-insert-fields/index.js +4 -0
- package/dist/transforms/remove-storage-always-insert-fields/index.js.map +1 -1
- package/dist/transforms/rename-diff-value-props/basic.input.js +38 -0
- package/dist/transforms/rename-diff-value-props/basic.input.js.map +1 -0
- package/dist/transforms/rename-diff-value-props/basic.output.js +38 -0
- package/dist/transforms/rename-diff-value-props/basic.output.js.map +1 -0
- package/dist/transforms/rename-diff-value-props/index.d.ts +3 -0
- package/dist/transforms/rename-diff-value-props/index.d.ts.map +1 -0
- package/dist/transforms/rename-diff-value-props/index.js +328 -0
- package/dist/transforms/rename-diff-value-props/index.js.map +1 -0
- package/dist/transforms/rename-diff-value-props/no-match.input.js +8 -0
- package/dist/transforms/rename-diff-value-props/no-match.input.js.map +1 -0
- package/dist/transforms/rename-experimental-table-feature/index.d.ts.map +1 -1
- package/dist/transforms/rename-experimental-table-feature/index.js +7 -1
- package/dist/transforms/rename-experimental-table-feature/index.js.map +1 -1
- package/dist/upgrade/defaultTag.d.ts +1 -1
- package/dist/upgrade/defaultTag.js +2 -2
- package/dist/upgrade/defaultTag.js.map +1 -1
- package/dist/upgrade/prompt.js +2 -2
- package/dist/upgrade/prompt.js.map +1 -1
- package/dist/upgrade/rewritePackageJson.d.ts.map +1 -1
- package/dist/upgrade/rewritePackageJson.js +52 -11
- package/dist/upgrade/rewritePackageJson.js.map +1 -1
- package/dist/utils/project.d.ts +7 -1
- package/dist/utils/project.d.ts.map +1 -1
- package/dist/utils/project.js +20 -7
- package/dist/utils/project.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export const Destructured = ({ comparisonValue, field, versionValue })=>{
|
|
2
|
+
const hasChanged = comparisonValue !== versionValue;
|
|
3
|
+
return hasChanged ? `${String(comparisonValue)} -> ${String(versionValue)}` : field.name;
|
|
4
|
+
};
|
|
5
|
+
export const LegacyComponentType = ({ comparisonValue, versionValue = '' })=>`${String(comparisonValue)} -> ${String(versionValue)}`;
|
|
6
|
+
export const Aliased = ({ comparisonValue: before, versionValue: valueTo })=>[
|
|
7
|
+
before,
|
|
8
|
+
valueTo
|
|
9
|
+
];
|
|
10
|
+
export default async function PropsObject(props) {
|
|
11
|
+
const { comparisonValue, req } = props;
|
|
12
|
+
return [
|
|
13
|
+
comparisonValue,
|
|
14
|
+
props.versionValue,
|
|
15
|
+
props['comparisonValue'],
|
|
16
|
+
req.locale
|
|
17
|
+
];
|
|
18
|
+
}
|
|
19
|
+
export function LocalPropsType({ label, versionValue }) {
|
|
20
|
+
return [
|
|
21
|
+
label,
|
|
22
|
+
versionValue
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
export const RestProps = ({ field, ...rest })=>[
|
|
26
|
+
field,
|
|
27
|
+
rest.comparisonValue
|
|
28
|
+
];
|
|
29
|
+
export const NameCollision = ({ comparisonValue })=>{
|
|
30
|
+
const valueFrom = 'unrelated';
|
|
31
|
+
return [
|
|
32
|
+
comparisonValue,
|
|
33
|
+
valueFrom
|
|
34
|
+
];
|
|
35
|
+
};
|
|
36
|
+
export const formatValue = (value)=>String(value);
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=basic.input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/transforms/rename-diff-value-props/basic.input.ts"],"sourcesContent":["import type {\n FieldDiffServerProps,\n TextFieldDiffClientComponent,\n TextFieldDiffClientProps,\n TextFieldDiffServerProps,\n} from 'payload'\nimport type React from 'react'\n\nexport const Destructured: React.FC<TextFieldDiffClientProps> = ({\n comparisonValue,\n field,\n versionValue,\n}) => {\n const hasChanged = comparisonValue !== versionValue\n return hasChanged ? `${String(comparisonValue)} -> ${String(versionValue)}` : field.name\n}\n\nexport const LegacyComponentType: TextFieldDiffClientComponent = ({\n comparisonValue,\n versionValue = '',\n}) => `${String(comparisonValue)} -> ${String(versionValue)}`\n\nexport const Aliased = ({\n comparisonValue: before,\n versionValue: valueTo,\n}: TextFieldDiffClientProps) => [before, valueTo]\n\nexport default async function PropsObject(props: TextFieldDiffServerProps) {\n const { comparisonValue, req } = props\n return [comparisonValue, props.versionValue, props['comparisonValue'], req.locale]\n}\n\ntype PropsWithLabel = { label: string } & TextFieldDiffClientProps\n\nexport function LocalPropsType({ label, versionValue }: PropsWithLabel) {\n return [label, versionValue]\n}\n\nexport const RestProps = ({ field, ...rest }: FieldDiffServerProps) => [field, rest.comparisonValue]\n\nexport const NameCollision = ({ comparisonValue }: TextFieldDiffClientProps) => {\n const valueFrom = 'unrelated'\n return [comparisonValue, valueFrom]\n}\n\nexport const formatValue = (value: TextFieldDiffClientProps['versionValue']) => String(value)\n"],"names":["Destructured","comparisonValue","field","versionValue","hasChanged","String","name","LegacyComponentType","Aliased","before","valueTo","PropsObject","props","req","locale","LocalPropsType","label","RestProps","rest","NameCollision","valueFrom","formatValue","value"],"mappings":"AAQA,OAAO,MAAMA,eAAmD,CAAC,EAC/DC,eAAe,EACfC,KAAK,EACLC,YAAY,EACb;IACC,MAAMC,aAAaH,oBAAoBE;IACvC,OAAOC,aAAa,GAAGC,OAAOJ,iBAAiB,IAAI,EAAEI,OAAOF,eAAe,GAAGD,MAAMI,IAAI;AAC1F,EAAC;AAED,OAAO,MAAMC,sBAAoD,CAAC,EAChEN,eAAe,EACfE,eAAe,EAAE,EAClB,GAAK,GAAGE,OAAOJ,iBAAiB,IAAI,EAAEI,OAAOF,eAAe,CAAA;AAE7D,OAAO,MAAMK,UAAU,CAAC,EACtBP,iBAAiBQ,MAAM,EACvBN,cAAcO,OAAO,EACI,GAAK;QAACD;QAAQC;KAAQ,CAAA;AAEjD,eAAe,eAAeC,YAAYC,KAA+B;IACvE,MAAM,EAAEX,eAAe,EAAEY,GAAG,EAAE,GAAGD;IACjC,OAAO;QAACX;QAAiBW,MAAMT,YAAY;QAAES,KAAK,CAAC,kBAAkB;QAAEC,IAAIC,MAAM;KAAC;AACpF;AAIA,OAAO,SAASC,eAAe,EAAEC,KAAK,EAAEb,YAAY,EAAkB;IACpE,OAAO;QAACa;QAAOb;KAAa;AAC9B;AAEA,OAAO,MAAMc,YAAY,CAAC,EAAEf,KAAK,EAAE,GAAGgB,MAA4B,GAAK;QAAChB;QAAOgB,KAAKjB,eAAe;KAAC,CAAA;AAEpG,OAAO,MAAMkB,gBAAgB,CAAC,EAAElB,eAAe,EAA4B;IACzE,MAAMmB,YAAY;IAClB,OAAO;QAACnB;QAAiBmB;KAAU;AACrC,EAAC;AAED,OAAO,MAAMC,cAAc,CAACC,QAAoDjB,OAAOiB,OAAM"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export const Destructured = ({ valueFrom, field, valueTo })=>{
|
|
2
|
+
const hasChanged = valueFrom !== valueTo;
|
|
3
|
+
return hasChanged ? `${String(valueFrom)} -> ${String(valueTo)}` : field.name;
|
|
4
|
+
};
|
|
5
|
+
export const LegacyComponentType = ({ valueFrom, valueTo = '' })=>`${String(valueFrom)} -> ${String(valueTo)}`;
|
|
6
|
+
export const Aliased = ({ valueFrom: before, valueTo })=>[
|
|
7
|
+
before,
|
|
8
|
+
valueTo
|
|
9
|
+
];
|
|
10
|
+
export default async function PropsObject(props) {
|
|
11
|
+
const { valueFrom, req } = props;
|
|
12
|
+
return [
|
|
13
|
+
valueFrom,
|
|
14
|
+
props.valueTo,
|
|
15
|
+
props['valueFrom'],
|
|
16
|
+
req.locale
|
|
17
|
+
];
|
|
18
|
+
}
|
|
19
|
+
export function LocalPropsType({ label, valueTo }) {
|
|
20
|
+
return [
|
|
21
|
+
label,
|
|
22
|
+
valueTo
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
export const RestProps = ({ field, ...rest })=>[
|
|
26
|
+
field,
|
|
27
|
+
rest.valueFrom
|
|
28
|
+
];
|
|
29
|
+
export const NameCollision = ({ valueFrom: comparisonValue })=>{
|
|
30
|
+
const valueFrom = 'unrelated';
|
|
31
|
+
return [
|
|
32
|
+
comparisonValue,
|
|
33
|
+
valueFrom
|
|
34
|
+
];
|
|
35
|
+
};
|
|
36
|
+
export const formatValue = (value)=>String(value);
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=basic.output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/transforms/rename-diff-value-props/basic.output.ts"],"sourcesContent":["import type {\n FieldDiffServerProps,\n TextFieldDiffClientComponent,\n TextFieldDiffClientProps,\n TextFieldDiffServerProps,\n} from 'payload'\nimport type React from 'react'\n\nexport const Destructured: React.FC<TextFieldDiffClientProps> = ({\n valueFrom,\n field,\n valueTo,\n}) => {\n const hasChanged = valueFrom !== valueTo\n return hasChanged ? `${String(valueFrom)} -> ${String(valueTo)}` : field.name\n}\n\nexport const LegacyComponentType: TextFieldDiffClientComponent = ({\n valueFrom,\n valueTo = '',\n}) => `${String(valueFrom)} -> ${String(valueTo)}`\n\nexport const Aliased = ({\n valueFrom: before,\n valueTo,\n}: TextFieldDiffClientProps) => [before, valueTo]\n\nexport default async function PropsObject(props: TextFieldDiffServerProps) {\n const { valueFrom, req } = props\n return [valueFrom, props.valueTo, props['valueFrom'], req.locale]\n}\n\ntype PropsWithLabel = { label: string } & TextFieldDiffClientProps\n\nexport function LocalPropsType({ label, valueTo }: PropsWithLabel) {\n return [label, valueTo]\n}\n\nexport const RestProps = ({ field, ...rest }: FieldDiffServerProps) => [field, rest.valueFrom]\n\nexport const NameCollision = ({ valueFrom: comparisonValue }: TextFieldDiffClientProps) => {\n const valueFrom = 'unrelated'\n return [comparisonValue, valueFrom]\n}\n\nexport const formatValue = (value: TextFieldDiffClientProps['valueTo']) => String(value)\n"],"names":["Destructured","valueFrom","field","valueTo","hasChanged","String","name","LegacyComponentType","Aliased","before","PropsObject","props","req","locale","LocalPropsType","label","RestProps","rest","NameCollision","comparisonValue","formatValue","value"],"mappings":"AAQA,OAAO,MAAMA,eAAmD,CAAC,EAC/DC,SAAS,EACTC,KAAK,EACLC,OAAO,EACR;IACC,MAAMC,aAAaH,cAAcE;IACjC,OAAOC,aAAa,GAAGC,OAAOJ,WAAW,IAAI,EAAEI,OAAOF,UAAU,GAAGD,MAAMI,IAAI;AAC/E,EAAC;AAED,OAAO,MAAMC,sBAAoD,CAAC,EAChEN,SAAS,EACTE,UAAU,EAAE,EACb,GAAK,GAAGE,OAAOJ,WAAW,IAAI,EAAEI,OAAOF,UAAU,CAAA;AAElD,OAAO,MAAMK,UAAU,CAAC,EACtBP,WAAWQ,MAAM,EACjBN,OAAO,EACkB,GAAK;QAACM;QAAQN;KAAQ,CAAA;AAEjD,eAAe,eAAeO,YAAYC,KAA+B;IACvE,MAAM,EAAEV,SAAS,EAAEW,GAAG,EAAE,GAAGD;IAC3B,OAAO;QAACV;QAAWU,MAAMR,OAAO;QAAEQ,KAAK,CAAC,YAAY;QAAEC,IAAIC,MAAM;KAAC;AACnE;AAIA,OAAO,SAASC,eAAe,EAAEC,KAAK,EAAEZ,OAAO,EAAkB;IAC/D,OAAO;QAACY;QAAOZ;KAAQ;AACzB;AAEA,OAAO,MAAMa,YAAY,CAAC,EAAEd,KAAK,EAAE,GAAGe,MAA4B,GAAK;QAACf;QAAOe,KAAKhB,SAAS;KAAC,CAAA;AAE9F,OAAO,MAAMiB,gBAAgB,CAAC,EAAEjB,WAAWkB,eAAe,EAA4B;IACpF,MAAMlB,YAAY;IAClB,OAAO;QAACkB;QAAiBlB;KAAU;AACrC,EAAC;AAED,OAAO,MAAMmB,cAAc,CAACC,QAA+ChB,OAAOgB,OAAM"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transforms/rename-diff-value-props/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAsB/C,eAAO,MAAM,oBAAoB,EAAE,SAwClC,CAAA"}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { Node, SyntaxKind } from 'ts-morph';
|
|
2
|
+
const RENAMED_PROPS = new Map([
|
|
3
|
+
[
|
|
4
|
+
'comparisonValue',
|
|
5
|
+
'valueFrom'
|
|
6
|
+
],
|
|
7
|
+
[
|
|
8
|
+
'versionValue',
|
|
9
|
+
'valueTo'
|
|
10
|
+
]
|
|
11
|
+
]);
|
|
12
|
+
/**
|
|
13
|
+
* Matches every Diff component type exported from `payload`, in both the v3 component-alias
|
|
14
|
+
* form (`TextFieldDiffClientComponent`) and the props form (`TextFieldDiffClientProps`), so this
|
|
15
|
+
* transform works regardless of whether `migrate-field-component-types` has already run.
|
|
16
|
+
*/ const DIFF_TYPE_NAME_PATTERN = /^[A-Za-z]*FieldDiff(?:Client|Server)(?:Component|Props)$/;
|
|
17
|
+
/**
|
|
18
|
+
* Every rewrite removes one old prop name, so the per-file loop always terminates. This cap only
|
|
19
|
+
* guards against an unexpected regression turning it into an infinite loop.
|
|
20
|
+
*/ const MAX_REWRITES_PER_FILE = 1000;
|
|
21
|
+
export const renameDiffValueProps = {
|
|
22
|
+
name: 'rename-diff-value-props',
|
|
23
|
+
apply: ({ project })=>{
|
|
24
|
+
const filesChanged = [];
|
|
25
|
+
const notes = [];
|
|
26
|
+
for (const sourceFile of project.getSourceFiles()){
|
|
27
|
+
if (sourceFile.isDeclarationFile() || sourceFile.isInNodeModules()) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const diffTypeNames = collectDiffTypeNames({
|
|
31
|
+
sourceFile
|
|
32
|
+
});
|
|
33
|
+
if (diffTypeNames.size === 0) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
let rewriteCount = 0;
|
|
37
|
+
while(rewriteCount < MAX_REWRITES_PER_FILE && rewriteNextOccurrence({
|
|
38
|
+
diffTypeNames,
|
|
39
|
+
sourceFile
|
|
40
|
+
})){
|
|
41
|
+
rewriteCount++;
|
|
42
|
+
}
|
|
43
|
+
if (rewriteCount > 0) {
|
|
44
|
+
filesChanged.push(sourceFile.getFilePath());
|
|
45
|
+
}
|
|
46
|
+
notes.push(...collectLeftoverNotes({
|
|
47
|
+
sourceFile
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
filesChanged,
|
|
52
|
+
...notes.length > 0 ? {
|
|
53
|
+
notes
|
|
54
|
+
} : {}
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
description: 'Rename the `comparisonValue` and `versionValue` props read by custom Diff components to `valueFrom` and `valueTo`.'
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Returns the local names of Diff component types imported from `payload`, plus same-file type
|
|
61
|
+
* aliases and interfaces built from them (e.g. `type Props = TextFieldDiffClientProps & { ... }`).
|
|
62
|
+
*/ function collectDiffTypeNames({ sourceFile }) {
|
|
63
|
+
const diffTypeNames = new Set();
|
|
64
|
+
for (const importDeclaration of sourceFile.getImportDeclarations()){
|
|
65
|
+
if (importDeclaration.getModuleSpecifierValue() !== 'payload') {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
for (const namedImport of importDeclaration.getNamedImports()){
|
|
69
|
+
if (DIFF_TYPE_NAME_PATTERN.test(namedImport.getName())) {
|
|
70
|
+
diffTypeNames.add(namedImport.getAliasNode()?.getText() ?? namedImport.getName());
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (diffTypeNames.size === 0) {
|
|
75
|
+
return diffTypeNames;
|
|
76
|
+
}
|
|
77
|
+
let hasFoundNewName = true;
|
|
78
|
+
while(hasFoundNewName){
|
|
79
|
+
hasFoundNewName = false;
|
|
80
|
+
const derivedTypeNames = [
|
|
81
|
+
...sourceFile.getTypeAliases().filter((typeAlias)=>referencesDiffType({
|
|
82
|
+
diffTypeNames,
|
|
83
|
+
typeNode: typeAlias.getTypeNodeOrThrow()
|
|
84
|
+
})),
|
|
85
|
+
...sourceFile.getInterfaces().filter((declaration)=>declaration.getExtends().some((heritage)=>diffTypeNames.has(heritage.getExpression().getText())))
|
|
86
|
+
].map((declaration)=>declaration.getName());
|
|
87
|
+
for (const typeName of derivedTypeNames){
|
|
88
|
+
if (!diffTypeNames.has(typeName)) {
|
|
89
|
+
diffTypeNames.add(typeName);
|
|
90
|
+
hasFoundNewName = true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return diffTypeNames;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Applies a single rewrite and reports whether one was made. Renames replace source text, which
|
|
98
|
+
* invalidates previously queried nodes, so the caller re-scans the file after every rewrite.
|
|
99
|
+
*/ function rewriteNextOccurrence({ diffTypeNames, sourceFile }) {
|
|
100
|
+
for (const component of findDiffComponents({
|
|
101
|
+
diffTypeNames,
|
|
102
|
+
sourceFile
|
|
103
|
+
})){
|
|
104
|
+
const propsParameterName = component.getParameters()[0].getNameNode();
|
|
105
|
+
const propsBindingPatterns = [];
|
|
106
|
+
const propsIdentifiers = [];
|
|
107
|
+
if (Node.isObjectBindingPattern(propsParameterName)) {
|
|
108
|
+
propsBindingPatterns.push(propsParameterName);
|
|
109
|
+
const restElementName = propsParameterName.getElements().find((element)=>element.getDotDotDotToken())?.getNameNode();
|
|
110
|
+
if (restElementName && Node.isIdentifier(restElementName)) {
|
|
111
|
+
propsIdentifiers.push(restElementName);
|
|
112
|
+
}
|
|
113
|
+
} else if (Node.isIdentifier(propsParameterName)) {
|
|
114
|
+
propsIdentifiers.push(propsParameterName);
|
|
115
|
+
}
|
|
116
|
+
const readsProps = (node)=>Node.isIdentifier(node) && propsIdentifiers.some((propsIdentifier)=>isReferenceTo({
|
|
117
|
+
declaration: propsIdentifier,
|
|
118
|
+
identifier: node
|
|
119
|
+
}));
|
|
120
|
+
for (const declaration of component.getDescendantsOfKind(SyntaxKind.VariableDeclaration)){
|
|
121
|
+
const declarationName = declaration.getNameNode();
|
|
122
|
+
const initializer = declaration.getInitializer();
|
|
123
|
+
if (Node.isObjectBindingPattern(declarationName) && initializer && readsProps(initializer)) {
|
|
124
|
+
propsBindingPatterns.push(declarationName);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
for (const pattern of propsBindingPatterns){
|
|
128
|
+
for (const element of pattern.getElements()){
|
|
129
|
+
if (rewriteBindingElement({
|
|
130
|
+
component,
|
|
131
|
+
element
|
|
132
|
+
})) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
for (const access of component.getDescendantsOfKind(SyntaxKind.PropertyAccessExpression)){
|
|
138
|
+
const newName = RENAMED_PROPS.get(access.getName());
|
|
139
|
+
if (newName && readsProps(access.getExpression())) {
|
|
140
|
+
access.getNameNode().replaceWithText(newName);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
for (const access of component.getDescendantsOfKind(SyntaxKind.ElementAccessExpression)){
|
|
145
|
+
const argument = access.getArgumentExpression();
|
|
146
|
+
if (!argument || !Node.isStringLiteral(argument) || !readsProps(access.getExpression())) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const newName = RENAMED_PROPS.get(argument.getLiteralValue());
|
|
150
|
+
if (newName) {
|
|
151
|
+
argument.setLiteralValue(newName);
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (const indexedAccess of sourceFile.getDescendantsOfKind(SyntaxKind.IndexedAccessType)){
|
|
157
|
+
const indexType = indexedAccess.getIndexTypeNode();
|
|
158
|
+
const literal = Node.isLiteralTypeNode(indexType) ? indexType.getLiteral() : undefined;
|
|
159
|
+
if (!literal || !Node.isStringLiteral(literal) || !referencesDiffType({
|
|
160
|
+
diffTypeNames,
|
|
161
|
+
typeNode: indexedAccess.getObjectTypeNode()
|
|
162
|
+
})) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const newName = RENAMED_PROPS.get(literal.getLiteralValue());
|
|
166
|
+
if (newName) {
|
|
167
|
+
literal.setLiteralValue(newName);
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Finds functions whose first parameter is typed with a Diff type, either directly
|
|
175
|
+
* (`(props: TextFieldDiffClientProps) => ...`) or through the variable they are assigned to
|
|
176
|
+
* (`const Diff: React.FC<TextFieldDiffClientProps> = (props) => ...`).
|
|
177
|
+
*/ function findDiffComponents({ diffTypeNames, sourceFile }) {
|
|
178
|
+
const functions = [
|
|
179
|
+
...sourceFile.getDescendantsOfKind(SyntaxKind.ArrowFunction),
|
|
180
|
+
...sourceFile.getDescendantsOfKind(SyntaxKind.FunctionDeclaration),
|
|
181
|
+
...sourceFile.getDescendantsOfKind(SyntaxKind.FunctionExpression)
|
|
182
|
+
];
|
|
183
|
+
return functions.filter((component)=>{
|
|
184
|
+
const propsParameter = component.getParameters()[0];
|
|
185
|
+
if (!propsParameter) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
const parent = component.getParent();
|
|
189
|
+
const typeNodes = [
|
|
190
|
+
propsParameter.getTypeNode(),
|
|
191
|
+
Node.isVariableDeclaration(parent) ? parent.getTypeNode() : undefined
|
|
192
|
+
];
|
|
193
|
+
return typeNodes.some((typeNode)=>typeNode && referencesDiffType({
|
|
194
|
+
diffTypeNames,
|
|
195
|
+
typeNode
|
|
196
|
+
}));
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function referencesDiffType({ diffTypeNames, typeNode }) {
|
|
200
|
+
return [
|
|
201
|
+
typeNode,
|
|
202
|
+
...typeNode.getDescendantsOfKind(SyntaxKind.TypeReference)
|
|
203
|
+
].some((node)=>Node.isTypeReference(node) && diffTypeNames.has(node.getTypeName().getText()) && !isWrappedWithin({
|
|
204
|
+
node,
|
|
205
|
+
root: typeNode
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Whether `node` sits inside a type that wraps the props rather than describing them, such as
|
|
210
|
+
* `{ diff: TextFieldDiffClientProps }` or `TextFieldDiffClientProps['valueFrom']`.
|
|
211
|
+
*/ function isWrappedWithin({ node, root }) {
|
|
212
|
+
const stopAt = root.getParent();
|
|
213
|
+
for(let ancestor = node.getParent(); ancestor && ancestor !== stopAt; ancestor = ancestor.getParent()){
|
|
214
|
+
if (Node.isPropertySignature(ancestor) || Node.isIndexedAccessTypeNode(ancestor)) {
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Renames the destructured key of a single binding element. Returns `false` when the element
|
|
222
|
+
* doesn't destructure one of the renamed props.
|
|
223
|
+
*/ function rewriteBindingElement({ component, element }) {
|
|
224
|
+
if (element.getDotDotDotToken()) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
const nameNode = element.getNameNode();
|
|
228
|
+
const propertyNameNode = element.getPropertyNameNode();
|
|
229
|
+
const propertyName = propertyNameNode ? getPropertyNameText({
|
|
230
|
+
node: propertyNameNode
|
|
231
|
+
}) : nameNode.getText();
|
|
232
|
+
const newName = propertyName ? RENAMED_PROPS.get(propertyName) : undefined;
|
|
233
|
+
if (!propertyName || !newName) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
const initializer = element.getInitializer();
|
|
237
|
+
const initializerText = initializer ? ` = ${initializer.getText()}` : '';
|
|
238
|
+
if (propertyNameNode) {
|
|
239
|
+
const localName = nameNode.getText();
|
|
240
|
+
element.replaceWithText(localName === newName ? `${newName}${initializerText}` : `${newName}: ${localName}${initializerText}`);
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
// A shorthand `{ comparisonValue }` also declares a local variable. Renaming it through the
|
|
244
|
+
// language service updates every reference, and `usePrefixAndSuffixText` leaves the element as
|
|
245
|
+
// `comparisonValue: valueFrom`, which the next pass collapses to `valueFrom`.
|
|
246
|
+
if (Node.isIdentifier(nameNode) && !containsIdentifierNamed({
|
|
247
|
+
name: newName,
|
|
248
|
+
node: component
|
|
249
|
+
})) {
|
|
250
|
+
const sourceFile = element.getSourceFile();
|
|
251
|
+
const textBeforeRename = sourceFile.getFullText();
|
|
252
|
+
try {
|
|
253
|
+
nameNode.rename(newName, {
|
|
254
|
+
usePrefixAndSuffixText: true
|
|
255
|
+
});
|
|
256
|
+
} catch {
|
|
257
|
+
// Fall back to keeping the local variable name below
|
|
258
|
+
}
|
|
259
|
+
if (sourceFile.getFullText() !== textBeforeRename) {
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
element.replaceWithText(`${newName}: ${propertyName}${initializerText}`);
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
function getPropertyNameText({ node }) {
|
|
267
|
+
if (Node.isIdentifier(node)) {
|
|
268
|
+
return node.getText();
|
|
269
|
+
}
|
|
270
|
+
if (Node.isStringLiteral(node)) {
|
|
271
|
+
return node.getLiteralValue();
|
|
272
|
+
}
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
function containsIdentifierNamed({ name, node }) {
|
|
276
|
+
return node.getDescendantsOfKind(SyntaxKind.Identifier).some((identifier)=>identifier.getText() === name);
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Compares symbols so an inner variable that shadows the props parameter isn't mistaken for it.
|
|
280
|
+
* Falls back to comparing names when the type checker can't resolve a symbol.
|
|
281
|
+
*/ function isReferenceTo({ declaration, identifier }) {
|
|
282
|
+
if (identifier.getText() !== declaration.getText()) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
const declarationSymbol = declaration.getSymbol();
|
|
286
|
+
return !declarationSymbol || identifier.getSymbol() === declarationSymbol;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Flags old prop names that remain in a property position, e.g. a JSX attribute passing
|
|
290
|
+
* `comparisonValue` to another component, or `Pick<Props, 'versionValue'>`. Local variables that
|
|
291
|
+
* merely share the old name are left alone.
|
|
292
|
+
*/ function collectLeftoverNotes({ sourceFile }) {
|
|
293
|
+
const notedLocations = new Set();
|
|
294
|
+
const notes = [];
|
|
295
|
+
const candidates = [
|
|
296
|
+
...sourceFile.getDescendantsOfKind(SyntaxKind.Identifier).filter((identifier)=>isPropertyNamePosition({
|
|
297
|
+
identifier
|
|
298
|
+
})),
|
|
299
|
+
...sourceFile.getDescendantsOfKind(SyntaxKind.StringLiteral)
|
|
300
|
+
].sort((a, b)=>a.getStart() - b.getStart());
|
|
301
|
+
for (const candidate of candidates){
|
|
302
|
+
const oldName = Node.isStringLiteral(candidate) ? candidate.getLiteralValue() : candidate.getText();
|
|
303
|
+
const newName = RENAMED_PROPS.get(oldName);
|
|
304
|
+
const location = `${sourceFile.getFilePath()}:${candidate.getStartLineNumber()}`;
|
|
305
|
+
if (!newName || notedLocations.has(`${location}:${oldName}`)) {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
notedLocations.add(`${location}:${oldName}`);
|
|
309
|
+
notes.push(`${location}: \`${oldName}\` was not migrated. If it refers to a Diff component prop, rename it to \`${newName}\`.`);
|
|
310
|
+
}
|
|
311
|
+
return notes;
|
|
312
|
+
}
|
|
313
|
+
function isPropertyNamePosition({ identifier }) {
|
|
314
|
+
const parent = identifier.getParent();
|
|
315
|
+
if (Node.isShorthandPropertyAssignment(parent) || Node.isJsxAttribute(parent)) {
|
|
316
|
+
return true;
|
|
317
|
+
}
|
|
318
|
+
if (Node.isBindingElement(parent)) {
|
|
319
|
+
const propertyNameNode = parent.getPropertyNameNode();
|
|
320
|
+
return propertyNameNode ? propertyNameNode === identifier : !parent.getDotDotDotToken();
|
|
321
|
+
}
|
|
322
|
+
if (Node.isPropertyAccessExpression(parent) || Node.isPropertyAssignment(parent) || Node.isPropertySignature(parent)) {
|
|
323
|
+
return parent.getNameNode() === identifier;
|
|
324
|
+
}
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/transforms/rename-diff-value-props/index.ts"],"sourcesContent":["import type {\n ArrowFunction,\n BindingElement,\n FunctionDeclaration,\n FunctionExpression,\n Identifier,\n ObjectBindingPattern,\n SourceFile,\n TypeNode,\n} from 'ts-morph'\n\nimport { Node, SyntaxKind } from 'ts-morph'\n\nimport type { Transform } from '../../types.js'\n\nconst RENAMED_PROPS = new Map([\n ['comparisonValue', 'valueFrom'],\n ['versionValue', 'valueTo'],\n])\n\n/**\n * Matches every Diff component type exported from `payload`, in both the v3 component-alias\n * form (`TextFieldDiffClientComponent`) and the props form (`TextFieldDiffClientProps`), so this\n * transform works regardless of whether `migrate-field-component-types` has already run.\n */\nconst DIFF_TYPE_NAME_PATTERN = /^[A-Za-z]*FieldDiff(?:Client|Server)(?:Component|Props)$/\n\n/**\n * Every rewrite removes one old prop name, so the per-file loop always terminates. This cap only\n * guards against an unexpected regression turning it into an infinite loop.\n */\nconst MAX_REWRITES_PER_FILE = 1000\n\ntype ComponentFunction = ArrowFunction | FunctionDeclaration | FunctionExpression\n\nexport const renameDiffValueProps: Transform = {\n name: 'rename-diff-value-props',\n apply: ({ project }) => {\n const filesChanged: string[] = []\n const notes: string[] = []\n\n for (const sourceFile of project.getSourceFiles()) {\n if (sourceFile.isDeclarationFile() || sourceFile.isInNodeModules()) {\n continue\n }\n\n const diffTypeNames = collectDiffTypeNames({ sourceFile })\n\n if (diffTypeNames.size === 0) {\n continue\n }\n\n let rewriteCount = 0\n\n while (\n rewriteCount < MAX_REWRITES_PER_FILE &&\n rewriteNextOccurrence({ diffTypeNames, sourceFile })\n ) {\n rewriteCount++\n }\n\n if (rewriteCount > 0) {\n filesChanged.push(sourceFile.getFilePath())\n }\n\n notes.push(...collectLeftoverNotes({ sourceFile }))\n }\n\n return {\n filesChanged,\n ...(notes.length > 0 ? { notes } : {}),\n }\n },\n description:\n 'Rename the `comparisonValue` and `versionValue` props read by custom Diff components to `valueFrom` and `valueTo`.',\n}\n\n/**\n * Returns the local names of Diff component types imported from `payload`, plus same-file type\n * aliases and interfaces built from them (e.g. `type Props = TextFieldDiffClientProps & { ... }`).\n */\nfunction collectDiffTypeNames({ sourceFile }: { sourceFile: SourceFile }): Set<string> {\n const diffTypeNames = new Set<string>()\n\n for (const importDeclaration of sourceFile.getImportDeclarations()) {\n if (importDeclaration.getModuleSpecifierValue() !== 'payload') {\n continue\n }\n\n for (const namedImport of importDeclaration.getNamedImports()) {\n if (DIFF_TYPE_NAME_PATTERN.test(namedImport.getName())) {\n diffTypeNames.add(namedImport.getAliasNode()?.getText() ?? namedImport.getName())\n }\n }\n }\n\n if (diffTypeNames.size === 0) {\n return diffTypeNames\n }\n\n let hasFoundNewName = true\n\n while (hasFoundNewName) {\n hasFoundNewName = false\n\n const derivedTypeNames = [\n ...sourceFile\n .getTypeAliases()\n .filter((typeAlias) =>\n referencesDiffType({ diffTypeNames, typeNode: typeAlias.getTypeNodeOrThrow() }),\n ),\n ...sourceFile\n .getInterfaces()\n .filter((declaration) =>\n declaration\n .getExtends()\n .some((heritage) => diffTypeNames.has(heritage.getExpression().getText())),\n ),\n ].map((declaration) => declaration.getName())\n\n for (const typeName of derivedTypeNames) {\n if (!diffTypeNames.has(typeName)) {\n diffTypeNames.add(typeName)\n hasFoundNewName = true\n }\n }\n }\n\n return diffTypeNames\n}\n\n/**\n * Applies a single rewrite and reports whether one was made. Renames replace source text, which\n * invalidates previously queried nodes, so the caller re-scans the file after every rewrite.\n */\nfunction rewriteNextOccurrence({\n diffTypeNames,\n sourceFile,\n}: {\n diffTypeNames: Set<string>\n sourceFile: SourceFile\n}): boolean {\n for (const component of findDiffComponents({ diffTypeNames, sourceFile })) {\n const propsParameterName = component.getParameters()[0]!.getNameNode()\n const propsBindingPatterns: ObjectBindingPattern[] = []\n const propsIdentifiers: Identifier[] = []\n\n if (Node.isObjectBindingPattern(propsParameterName)) {\n propsBindingPatterns.push(propsParameterName)\n\n const restElementName = propsParameterName\n .getElements()\n .find((element) => element.getDotDotDotToken())\n ?.getNameNode()\n\n if (restElementName && Node.isIdentifier(restElementName)) {\n propsIdentifiers.push(restElementName)\n }\n } else if (Node.isIdentifier(propsParameterName)) {\n propsIdentifiers.push(propsParameterName)\n }\n\n const readsProps = (node: Node): boolean =>\n Node.isIdentifier(node) &&\n propsIdentifiers.some((propsIdentifier) =>\n isReferenceTo({ declaration: propsIdentifier, identifier: node }),\n )\n\n for (const declaration of component.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {\n const declarationName = declaration.getNameNode()\n const initializer = declaration.getInitializer()\n\n if (Node.isObjectBindingPattern(declarationName) && initializer && readsProps(initializer)) {\n propsBindingPatterns.push(declarationName)\n }\n }\n\n for (const pattern of propsBindingPatterns) {\n for (const element of pattern.getElements()) {\n if (rewriteBindingElement({ component, element })) {\n return true\n }\n }\n }\n\n for (const access of component.getDescendantsOfKind(SyntaxKind.PropertyAccessExpression)) {\n const newName = RENAMED_PROPS.get(access.getName())\n\n if (newName && readsProps(access.getExpression())) {\n access.getNameNode().replaceWithText(newName)\n return true\n }\n }\n\n for (const access of component.getDescendantsOfKind(SyntaxKind.ElementAccessExpression)) {\n const argument = access.getArgumentExpression()\n\n if (!argument || !Node.isStringLiteral(argument) || !readsProps(access.getExpression())) {\n continue\n }\n\n const newName = RENAMED_PROPS.get(argument.getLiteralValue())\n\n if (newName) {\n argument.setLiteralValue(newName)\n return true\n }\n }\n }\n\n for (const indexedAccess of sourceFile.getDescendantsOfKind(SyntaxKind.IndexedAccessType)) {\n const indexType = indexedAccess.getIndexTypeNode()\n const literal = Node.isLiteralTypeNode(indexType) ? indexType.getLiteral() : undefined\n\n if (\n !literal ||\n !Node.isStringLiteral(literal) ||\n !referencesDiffType({ diffTypeNames, typeNode: indexedAccess.getObjectTypeNode() })\n ) {\n continue\n }\n\n const newName = RENAMED_PROPS.get(literal.getLiteralValue())\n\n if (newName) {\n literal.setLiteralValue(newName)\n return true\n }\n }\n\n return false\n}\n\n/**\n * Finds functions whose first parameter is typed with a Diff type, either directly\n * (`(props: TextFieldDiffClientProps) => ...`) or through the variable they are assigned to\n * (`const Diff: React.FC<TextFieldDiffClientProps> = (props) => ...`).\n */\nfunction findDiffComponents({\n diffTypeNames,\n sourceFile,\n}: {\n diffTypeNames: Set<string>\n sourceFile: SourceFile\n}): ComponentFunction[] {\n const functions: ComponentFunction[] = [\n ...sourceFile.getDescendantsOfKind(SyntaxKind.ArrowFunction),\n ...sourceFile.getDescendantsOfKind(SyntaxKind.FunctionDeclaration),\n ...sourceFile.getDescendantsOfKind(SyntaxKind.FunctionExpression),\n ]\n\n return functions.filter((component) => {\n const propsParameter = component.getParameters()[0]\n\n if (!propsParameter) {\n return false\n }\n\n const parent = component.getParent()\n const typeNodes = [\n propsParameter.getTypeNode(),\n Node.isVariableDeclaration(parent) ? parent.getTypeNode() : undefined,\n ]\n\n return typeNodes.some((typeNode) => typeNode && referencesDiffType({ diffTypeNames, typeNode }))\n })\n}\n\nfunction referencesDiffType({\n diffTypeNames,\n typeNode,\n}: {\n diffTypeNames: Set<string>\n typeNode: TypeNode\n}): boolean {\n return [typeNode, ...typeNode.getDescendantsOfKind(SyntaxKind.TypeReference)].some(\n (node) =>\n Node.isTypeReference(node) &&\n diffTypeNames.has(node.getTypeName().getText()) &&\n !isWrappedWithin({ node, root: typeNode }),\n )\n}\n\n/**\n * Whether `node` sits inside a type that wraps the props rather than describing them, such as\n * `{ diff: TextFieldDiffClientProps }` or `TextFieldDiffClientProps['valueFrom']`.\n */\nfunction isWrappedWithin({ node, root }: { node: Node; root: TypeNode }): boolean {\n const stopAt = root.getParent()\n\n for (\n let ancestor = node.getParent();\n ancestor && ancestor !== stopAt;\n ancestor = ancestor.getParent()\n ) {\n if (Node.isPropertySignature(ancestor) || Node.isIndexedAccessTypeNode(ancestor)) {\n return true\n }\n }\n\n return false\n}\n\n/**\n * Renames the destructured key of a single binding element. Returns `false` when the element\n * doesn't destructure one of the renamed props.\n */\nfunction rewriteBindingElement({\n component,\n element,\n}: {\n component: ComponentFunction\n element: BindingElement\n}): boolean {\n if (element.getDotDotDotToken()) {\n return false\n }\n\n const nameNode = element.getNameNode()\n const propertyNameNode = element.getPropertyNameNode()\n const propertyName = propertyNameNode\n ? getPropertyNameText({ node: propertyNameNode })\n : nameNode.getText()\n const newName = propertyName ? RENAMED_PROPS.get(propertyName) : undefined\n\n if (!propertyName || !newName) {\n return false\n }\n\n const initializer = element.getInitializer()\n const initializerText = initializer ? ` = ${initializer.getText()}` : ''\n\n if (propertyNameNode) {\n const localName = nameNode.getText()\n\n element.replaceWithText(\n localName === newName\n ? `${newName}${initializerText}`\n : `${newName}: ${localName}${initializerText}`,\n )\n return true\n }\n\n // A shorthand `{ comparisonValue }` also declares a local variable. Renaming it through the\n // language service updates every reference, and `usePrefixAndSuffixText` leaves the element as\n // `comparisonValue: valueFrom`, which the next pass collapses to `valueFrom`.\n if (Node.isIdentifier(nameNode) && !containsIdentifierNamed({ name: newName, node: component })) {\n const sourceFile = element.getSourceFile()\n const textBeforeRename = sourceFile.getFullText()\n\n try {\n nameNode.rename(newName, { usePrefixAndSuffixText: true })\n } catch {\n // Fall back to keeping the local variable name below\n }\n\n if (sourceFile.getFullText() !== textBeforeRename) {\n return true\n }\n }\n\n element.replaceWithText(`${newName}: ${propertyName}${initializerText}`)\n return true\n}\n\nfunction getPropertyNameText({ node }: { node: Node }): string | undefined {\n if (Node.isIdentifier(node)) {\n return node.getText()\n }\n\n if (Node.isStringLiteral(node)) {\n return node.getLiteralValue()\n }\n\n return undefined\n}\n\nfunction containsIdentifierNamed({ name, node }: { name: string; node: Node }): boolean {\n return node\n .getDescendantsOfKind(SyntaxKind.Identifier)\n .some((identifier) => identifier.getText() === name)\n}\n\n/**\n * Compares symbols so an inner variable that shadows the props parameter isn't mistaken for it.\n * Falls back to comparing names when the type checker can't resolve a symbol.\n */\nfunction isReferenceTo({\n declaration,\n identifier,\n}: {\n declaration: Identifier\n identifier: Identifier\n}): boolean {\n if (identifier.getText() !== declaration.getText()) {\n return false\n }\n\n const declarationSymbol = declaration.getSymbol()\n\n return !declarationSymbol || identifier.getSymbol() === declarationSymbol\n}\n\n/**\n * Flags old prop names that remain in a property position, e.g. a JSX attribute passing\n * `comparisonValue` to another component, or `Pick<Props, 'versionValue'>`. Local variables that\n * merely share the old name are left alone.\n */\nfunction collectLeftoverNotes({ sourceFile }: { sourceFile: SourceFile }): string[] {\n const notedLocations = new Set<string>()\n const notes: string[] = []\n const candidates = [\n ...sourceFile\n .getDescendantsOfKind(SyntaxKind.Identifier)\n .filter((identifier) => isPropertyNamePosition({ identifier })),\n ...sourceFile.getDescendantsOfKind(SyntaxKind.StringLiteral),\n ].sort((a, b) => a.getStart() - b.getStart())\n\n for (const candidate of candidates) {\n const oldName = Node.isStringLiteral(candidate)\n ? candidate.getLiteralValue()\n : candidate.getText()\n const newName = RENAMED_PROPS.get(oldName)\n const location = `${sourceFile.getFilePath()}:${candidate.getStartLineNumber()}`\n\n if (!newName || notedLocations.has(`${location}:${oldName}`)) {\n continue\n }\n\n notedLocations.add(`${location}:${oldName}`)\n notes.push(\n `${location}: \\`${oldName}\\` was not migrated. If it refers to a Diff component prop, rename it to \\`${newName}\\`.`,\n )\n }\n\n return notes\n}\n\nfunction isPropertyNamePosition({ identifier }: { identifier: Identifier }): boolean {\n const parent = identifier.getParent()\n\n if (Node.isShorthandPropertyAssignment(parent) || Node.isJsxAttribute(parent)) {\n return true\n }\n\n if (Node.isBindingElement(parent)) {\n const propertyNameNode = parent.getPropertyNameNode()\n\n return propertyNameNode ? propertyNameNode === identifier : !parent.getDotDotDotToken()\n }\n\n if (\n Node.isPropertyAccessExpression(parent) ||\n Node.isPropertyAssignment(parent) ||\n Node.isPropertySignature(parent)\n ) {\n return parent.getNameNode() === identifier\n }\n\n return false\n}\n"],"names":["Node","SyntaxKind","RENAMED_PROPS","Map","DIFF_TYPE_NAME_PATTERN","MAX_REWRITES_PER_FILE","renameDiffValueProps","name","apply","project","filesChanged","notes","sourceFile","getSourceFiles","isDeclarationFile","isInNodeModules","diffTypeNames","collectDiffTypeNames","size","rewriteCount","rewriteNextOccurrence","push","getFilePath","collectLeftoverNotes","length","description","Set","importDeclaration","getImportDeclarations","getModuleSpecifierValue","namedImport","getNamedImports","test","getName","add","getAliasNode","getText","hasFoundNewName","derivedTypeNames","getTypeAliases","filter","typeAlias","referencesDiffType","typeNode","getTypeNodeOrThrow","getInterfaces","declaration","getExtends","some","heritage","has","getExpression","map","typeName","component","findDiffComponents","propsParameterName","getParameters","getNameNode","propsBindingPatterns","propsIdentifiers","isObjectBindingPattern","restElementName","getElements","find","element","getDotDotDotToken","isIdentifier","readsProps","node","propsIdentifier","isReferenceTo","identifier","getDescendantsOfKind","VariableDeclaration","declarationName","initializer","getInitializer","pattern","rewriteBindingElement","access","PropertyAccessExpression","newName","get","replaceWithText","ElementAccessExpression","argument","getArgumentExpression","isStringLiteral","getLiteralValue","setLiteralValue","indexedAccess","IndexedAccessType","indexType","getIndexTypeNode","literal","isLiteralTypeNode","getLiteral","undefined","getObjectTypeNode","functions","ArrowFunction","FunctionDeclaration","FunctionExpression","propsParameter","parent","getParent","typeNodes","getTypeNode","isVariableDeclaration","TypeReference","isTypeReference","getTypeName","isWrappedWithin","root","stopAt","ancestor","isPropertySignature","isIndexedAccessTypeNode","nameNode","propertyNameNode","getPropertyNameNode","propertyName","getPropertyNameText","initializerText","localName","containsIdentifierNamed","getSourceFile","textBeforeRename","getFullText","rename","usePrefixAndSuffixText","Identifier","declarationSymbol","getSymbol","notedLocations","candidates","isPropertyNamePosition","StringLiteral","sort","a","b","getStart","candidate","oldName","location","getStartLineNumber","isShorthandPropertyAssignment","isJsxAttribute","isBindingElement","isPropertyAccessExpression","isPropertyAssignment"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const isUnchanged = ({ comparisonValue, versionValue })=>comparisonValue === versionValue;
|
|
2
|
+
export const TextField = (props)=>props.versionValue;
|
|
3
|
+
export const versionValueField = {
|
|
4
|
+
name: 'versionValue',
|
|
5
|
+
type: 'text'
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=no-match.input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/transforms/rename-diff-value-props/no-match.input.ts"],"sourcesContent":["import type { Field, TextFieldClientProps } from 'payload'\n\ntype Comparison = { comparisonValue: unknown; versionValue: unknown }\n\nexport const isUnchanged = ({ comparisonValue, versionValue }: Comparison) =>\n comparisonValue === versionValue\n\nexport const TextField = (props: TextFieldClientProps & Comparison) => props.versionValue\n\nexport const versionValueField: Field = { name: 'versionValue', type: 'text' }\n"],"names":["isUnchanged","comparisonValue","versionValue","TextField","props","versionValueField","name","type"],"mappings":"AAIA,OAAO,MAAMA,cAAc,CAAC,EAAEC,eAAe,EAAEC,YAAY,EAAc,GACvED,oBAAoBC,aAAY;AAElC,OAAO,MAAMC,YAAY,CAACC,QAA6CA,MAAMF,YAAY,CAAA;AAEzF,OAAO,MAAMG,oBAA2B;IAAEC,MAAM;IAAgBC,MAAM;AAAO,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transforms/rename-experimental-table-feature/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transforms/rename-experimental-table-feature/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAM/C,eAAO,MAAM,8BAA8B,EAAE,SAkD5C,CAAA"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
1
2
|
const PACKAGE_NAME = '@payloadcms/richtext-lexical';
|
|
2
3
|
const OLD_NAME = 'EXPERIMENTAL_TableFeature';
|
|
3
4
|
const NEW_NAME = 'TableFeature';
|
|
@@ -27,7 +28,12 @@ export const renameExperimentalTableFeature = {
|
|
|
27
28
|
} else {
|
|
28
29
|
// No alias: the imported name is also the local binding, so rename it to update
|
|
29
30
|
// every call site (e.g. `EXPERIMENTAL_TableFeature()`) in the same pass.
|
|
30
|
-
spec.getNameNode()
|
|
31
|
+
const nameNode = spec.getNameNode();
|
|
32
|
+
// Always an Identifier in valid code: a string-literal import name requires an alias.
|
|
33
|
+
if (!Node.isIdentifier(nameNode)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
nameNode.rename(NEW_NAME);
|
|
31
37
|
}
|
|
32
38
|
filesChanged.add(file.getFilePath());
|
|
33
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/transforms/rename-experimental-table-feature/index.ts"],"sourcesContent":["import type { Transform } from '../../types.js'\n\nconst PACKAGE_NAME = '@payloadcms/richtext-lexical'\nconst OLD_NAME = 'EXPERIMENTAL_TableFeature'\nconst NEW_NAME = 'TableFeature'\n\nexport const renameExperimentalTableFeature: Transform = {\n name: 'rename-experimental-table-feature',\n apply: ({ project }) => {\n const filesChanged = new Set<string>()\n\n for (const file of project.getSourceFiles()) {\n for (const importDecl of file.getImportDeclarations()) {\n if (importDecl.getModuleSpecifierValue() !== PACKAGE_NAME) {\n continue\n }\n\n const named = importDecl.getNamedImports()\n const spec = named.find((specifier) => specifier.getName() === OLD_NAME)\n if (!spec) {\n continue\n }\n\n // Skip if `TableFeature` is already imported here too, to avoid a collision.\n const hasNewName = named.some(\n (specifier) => (specifier.getAliasNode()?.getText() ?? specifier.getName()) === NEW_NAME,\n )\n if (hasNewName) {\n continue\n }\n\n if (spec.getAliasNode()) {\n // Aliased usages (`EXPERIMENTAL_TableFeature as Foo`) only reference the alias,\n // so the imported name can be swapped without touching call sites.\n spec.setName(NEW_NAME)\n } else {\n // No alias: the imported name is also the local binding, so rename it to update\n // every call site (e.g. `EXPERIMENTAL_TableFeature()`) in the same pass.\n spec.getNameNode().rename(NEW_NAME)\n }\n\n filesChanged.add(file.getFilePath())\n }\n }\n\n return { filesChanged: [...filesChanged] }\n },\n description:\n 'Renames imports of `EXPERIMENTAL_TableFeature` from `@payloadcms/richtext-lexical` to `TableFeature` (the table feature is now stable) and updates all local usages.',\n}\n"],"names":["PACKAGE_NAME","OLD_NAME","NEW_NAME","renameExperimentalTableFeature","name","apply","project","filesChanged","Set","file","getSourceFiles","importDecl","getImportDeclarations","getModuleSpecifierValue","named","getNamedImports","spec","find","specifier","getName","hasNewName","some","getAliasNode","getText","setName","getNameNode","rename","add","getFilePath","description"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/transforms/rename-experimental-table-feature/index.ts"],"sourcesContent":["import { Node } from 'ts-morph'\n\nimport type { Transform } from '../../types.js'\n\nconst PACKAGE_NAME = '@payloadcms/richtext-lexical'\nconst OLD_NAME = 'EXPERIMENTAL_TableFeature'\nconst NEW_NAME = 'TableFeature'\n\nexport const renameExperimentalTableFeature: Transform = {\n name: 'rename-experimental-table-feature',\n apply: ({ project }) => {\n const filesChanged = new Set<string>()\n\n for (const file of project.getSourceFiles()) {\n for (const importDecl of file.getImportDeclarations()) {\n if (importDecl.getModuleSpecifierValue() !== PACKAGE_NAME) {\n continue\n }\n\n const named = importDecl.getNamedImports()\n const spec = named.find((specifier) => specifier.getName() === OLD_NAME)\n if (!spec) {\n continue\n }\n\n // Skip if `TableFeature` is already imported here too, to avoid a collision.\n const hasNewName = named.some(\n (specifier) => (specifier.getAliasNode()?.getText() ?? specifier.getName()) === NEW_NAME,\n )\n if (hasNewName) {\n continue\n }\n\n if (spec.getAliasNode()) {\n // Aliased usages (`EXPERIMENTAL_TableFeature as Foo`) only reference the alias,\n // so the imported name can be swapped without touching call sites.\n spec.setName(NEW_NAME)\n } else {\n // No alias: the imported name is also the local binding, so rename it to update\n // every call site (e.g. `EXPERIMENTAL_TableFeature()`) in the same pass.\n const nameNode = spec.getNameNode()\n\n // Always an Identifier in valid code: a string-literal import name requires an alias.\n if (!Node.isIdentifier(nameNode)) {\n continue\n }\n\n nameNode.rename(NEW_NAME)\n }\n\n filesChanged.add(file.getFilePath())\n }\n }\n\n return { filesChanged: [...filesChanged] }\n },\n description:\n 'Renames imports of `EXPERIMENTAL_TableFeature` from `@payloadcms/richtext-lexical` to `TableFeature` (the table feature is now stable) and updates all local usages.',\n}\n"],"names":["Node","PACKAGE_NAME","OLD_NAME","NEW_NAME","renameExperimentalTableFeature","name","apply","project","filesChanged","Set","file","getSourceFiles","importDecl","getImportDeclarations","getModuleSpecifierValue","named","getNamedImports","spec","find","specifier","getName","hasNewName","some","getAliasNode","getText","setName","nameNode","getNameNode","isIdentifier","rename","add","getFilePath","description"],"mappings":"AAAA,SAASA,IAAI,QAAQ,WAAU;AAI/B,MAAMC,eAAe;AACrB,MAAMC,WAAW;AACjB,MAAMC,WAAW;AAEjB,OAAO,MAAMC,iCAA4C;IACvDC,MAAM;IACNC,OAAO,CAAC,EAAEC,OAAO,EAAE;QACjB,MAAMC,eAAe,IAAIC;QAEzB,KAAK,MAAMC,QAAQH,QAAQI,cAAc,GAAI;YAC3C,KAAK,MAAMC,cAAcF,KAAKG,qBAAqB,GAAI;gBACrD,IAAID,WAAWE,uBAAuB,OAAOb,cAAc;oBACzD;gBACF;gBAEA,MAAMc,QAAQH,WAAWI,eAAe;gBACxC,MAAMC,OAAOF,MAAMG,IAAI,CAAC,CAACC,YAAcA,UAAUC,OAAO,OAAOlB;gBAC/D,IAAI,CAACe,MAAM;oBACT;gBACF;gBAEA,6EAA6E;gBAC7E,MAAMI,aAAaN,MAAMO,IAAI,CAC3B,CAACH,YAAc,AAACA,CAAAA,UAAUI,YAAY,IAAIC,aAAaL,UAAUC,OAAO,EAAC,MAAOjB;gBAElF,IAAIkB,YAAY;oBACd;gBACF;gBAEA,IAAIJ,KAAKM,YAAY,IAAI;oBACvB,gFAAgF;oBAChF,mEAAmE;oBACnEN,KAAKQ,OAAO,CAACtB;gBACf,OAAO;oBACL,gFAAgF;oBAChF,yEAAyE;oBACzE,MAAMuB,WAAWT,KAAKU,WAAW;oBAEjC,sFAAsF;oBACtF,IAAI,CAAC3B,KAAK4B,YAAY,CAACF,WAAW;wBAChC;oBACF;oBAEAA,SAASG,MAAM,CAAC1B;gBAClB;gBAEAK,aAAasB,GAAG,CAACpB,KAAKqB,WAAW;YACnC;QACF;QAEA,OAAO;YAAEvB,cAAc;mBAAIA;aAAa;QAAC;IAC3C;IACAwB,aACE;AACJ,EAAC"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* the monorepo (this one included) is versioned and published in lockstep, so
|
|
4
4
|
* the dist-tag the codemod was invoked under (`npx @payloadcms/codemod@beta`)
|
|
5
5
|
* surfaces as its own version's prerelease id. Follow that train; fall back to
|
|
6
|
-
*
|
|
6
|
+
* beta for stable or local dev builds that carry no prerelease id.
|
|
7
7
|
*/
|
|
8
8
|
export declare function resolveDefaultTag(version?: string | undefined): string;
|
|
9
9
|
//# sourceMappingURL=defaultTag.d.ts.map
|
|
@@ -2,13 +2,13 @@ import { readFileSync } from 'node:fs';
|
|
|
2
2
|
import { dirname, resolve } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import semver from 'semver';
|
|
5
|
-
/** Dist-tag used when neither --tag nor the running version implies one. */ const FALLBACK_TAG = '
|
|
5
|
+
/** Dist-tag used when neither --tag nor the running version implies one. */ const FALLBACK_TAG = 'beta';
|
|
6
6
|
/**
|
|
7
7
|
* Default Payload dist-tag when the caller did not pass --tag. Every package in
|
|
8
8
|
* the monorepo (this one included) is versioned and published in lockstep, so
|
|
9
9
|
* the dist-tag the codemod was invoked under (`npx @payloadcms/codemod@beta`)
|
|
10
10
|
* surfaces as its own version's prerelease id. Follow that train; fall back to
|
|
11
|
-
*
|
|
11
|
+
* beta for stable or local dev builds that carry no prerelease id.
|
|
12
12
|
*/ export function resolveDefaultTag(version = readOwnVersion()) {
|
|
13
13
|
const id = version ? semver.prerelease(version)?.[0] : undefined;
|
|
14
14
|
return typeof id === 'string' ? id : FALLBACK_TAG;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/upgrade/defaultTag.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport semver from 'semver'\n\n/** Dist-tag used when neither --tag nor the running version implies one. */\nconst FALLBACK_TAG = '
|
|
1
|
+
{"version":3,"sources":["../../src/upgrade/defaultTag.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport semver from 'semver'\n\n/** Dist-tag used when neither --tag nor the running version implies one. */\nconst FALLBACK_TAG = 'beta'\n\n/**\n * Default Payload dist-tag when the caller did not pass --tag. Every package in\n * the monorepo (this one included) is versioned and published in lockstep, so\n * the dist-tag the codemod was invoked under (`npx @payloadcms/codemod@beta`)\n * surfaces as its own version's prerelease id. Follow that train; fall back to\n * beta for stable or local dev builds that carry no prerelease id.\n */\nexport function resolveDefaultTag(version: string | undefined = readOwnVersion()): string {\n const id = version ? semver.prerelease(version)?.[0] : undefined\n return typeof id === 'string' ? id : FALLBACK_TAG\n}\n\nfunction readOwnVersion(): string | undefined {\n try {\n const pkgPath = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', 'package.json')\n return JSON.parse(readFileSync(pkgPath, 'utf8')).version as string\n } catch {\n return undefined\n }\n}\n"],"names":["readFileSync","dirname","resolve","fileURLToPath","semver","FALLBACK_TAG","resolveDefaultTag","version","readOwnVersion","id","prerelease","undefined","pkgPath","url","JSON","parse"],"mappings":"AAAA,SAASA,YAAY,QAAQ,UAAS;AACtC,SAASC,OAAO,EAAEC,OAAO,QAAQ,YAAW;AAC5C,SAASC,aAAa,QAAQ,WAAU;AACxC,OAAOC,YAAY,SAAQ;AAE3B,0EAA0E,GAC1E,MAAMC,eAAe;AAErB;;;;;;CAMC,GACD,OAAO,SAASC,kBAAkBC,UAA8BC,gBAAgB;IAC9E,MAAMC,KAAKF,UAAUH,OAAOM,UAAU,CAACH,UAAU,CAAC,EAAE,GAAGI;IACvD,OAAO,OAAOF,OAAO,WAAWA,KAAKJ;AACvC;AAEA,SAASG;IACP,IAAI;QACF,MAAMI,UAAUV,QAAQD,QAAQE,cAAc,YAAYU,GAAG,IAAI,MAAM,MAAM;QAC7E,OAAOC,KAAKC,KAAK,CAACf,aAAaY,SAAS,SAASL,OAAO;IAC1D,EAAE,OAAM;QACN,OAAOI;IACT;AACF"}
|
package/dist/upgrade/prompt.js
CHANGED
|
@@ -30,8 +30,8 @@ Run this from the project root:
|
|
|
30
30
|
|
|
31
31
|
${command} upgrade run
|
|
32
32
|
|
|
33
|
-
By default it resolves Payload from the dist-tag this CLI was installed under (
|
|
34
|
-
|
|
33
|
+
By default it resolves Payload from the dist-tag this CLI was installed under (its own
|
|
34
|
+
prerelease id, else \`beta\`). Add \`--tag <dist-tag>\` to pin a specific one.
|
|
35
35
|
This pins the Payload packages to v4, removes conflicting overrides, writes the toolchain
|
|
36
36
|
floors, installs, and runs the AST transforms. Read its report:
|
|
37
37
|
- It prints the resolved payload version, the required Next target, and the path to the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/upgrade/prompt.ts"],"sourcesContent":["/**\n * Render the overarching agent prompt for a full Payload v3 -> v4 upgrade,\n * Next.js 16 included. The prompt is a thin orchestrator: it sequences the\n * gates, runs this package's `upgrade` command for the deterministic slice,\n * delegates Next.js to Next's own agent workflow, and points at the migration\n * guide for the judgment work rather than restating any of it. The text is\n * project-agnostic (the agent runs it from the project root). `command` is the\n * token that re-invokes this CLI, so a local checkout points followers at the\n * local build instead of the published package. Pure: the caller prints it.\n */\nexport function renderUpgradePrompt({\n command = 'npx @payloadcms/codemod',\n}: { command?: string } = {}): string {\n return `You are upgrading this project from Payload v3 to v4, Next.js 16 included.\n\nGround rule: resolution over intent. A step is done only when it installs, builds, and boots.\nNever report a task complete because the edit looks right. Confirm it. A silent gap reads as\n\"checked and fine\".\n\n## 0. Preconditions\n- Work on a clean git tree or a fresh branch.\n- Use Node >=24.15 (the exact engines floor is printed by the command in step 2).\n\n## 1. Pre-upgrade migrations (do these on v3, before touching versions)\nSome migrations need the v3 tooling that v4 deletes, so they MUST run before the upgrade:\n- Slate richtext is removed in v4. Migrate Slate -> Lexical while still on v3; the migration path\n is gone once the packages are pinned to v4.\n\nDo not proceed to step 2 until these are complete and committed.\n\n## 2. Payload mechanical slice\nRun this from the project root:\n\n ${command} upgrade run\n\nBy default it resolves Payload from the dist-tag this CLI was installed under (
|
|
1
|
+
{"version":3,"sources":["../../src/upgrade/prompt.ts"],"sourcesContent":["/**\n * Render the overarching agent prompt for a full Payload v3 -> v4 upgrade,\n * Next.js 16 included. The prompt is a thin orchestrator: it sequences the\n * gates, runs this package's `upgrade` command for the deterministic slice,\n * delegates Next.js to Next's own agent workflow, and points at the migration\n * guide for the judgment work rather than restating any of it. The text is\n * project-agnostic (the agent runs it from the project root). `command` is the\n * token that re-invokes this CLI, so a local checkout points followers at the\n * local build instead of the published package. Pure: the caller prints it.\n */\nexport function renderUpgradePrompt({\n command = 'npx @payloadcms/codemod',\n}: { command?: string } = {}): string {\n return `You are upgrading this project from Payload v3 to v4, Next.js 16 included.\n\nGround rule: resolution over intent. A step is done only when it installs, builds, and boots.\nNever report a task complete because the edit looks right. Confirm it. A silent gap reads as\n\"checked and fine\".\n\n## 0. Preconditions\n- Work on a clean git tree or a fresh branch.\n- Use Node >=24.15 (the exact engines floor is printed by the command in step 2).\n\n## 1. Pre-upgrade migrations (do these on v3, before touching versions)\nSome migrations need the v3 tooling that v4 deletes, so they MUST run before the upgrade:\n- Slate richtext is removed in v4. Migrate Slate -> Lexical while still on v3; the migration path\n is gone once the packages are pinned to v4.\n\nDo not proceed to step 2 until these are complete and committed.\n\n## 2. Payload mechanical slice\nRun this from the project root:\n\n ${command} upgrade run\n\nBy default it resolves Payload from the dist-tag this CLI was installed under (its own\nprerelease id, else \\`beta\\`). Add \\`--tag <dist-tag>\\` to pin a specific one.\nThis pins the Payload packages to v4, removes conflicting overrides, writes the toolchain\nfloors, installs, and runs the AST transforms. Read its report:\n- It prints the resolved payload version, the required Next target, and the path to the\n bundled runbook and migration guide. Use those paths below.\n- The unmet \\`@payloadcms/next\\` peer against Next 15 is EXPECTED at this point. Do NOT downgrade\n payload to satisfy it; step 3 resolves it by upgrading Next.\n- Do not hand-edit the versions it pinned.\n\n## 3. Next.js 16 (delegate to Next's workflow)\nPayload v4 requires Next 16. The command above did not touch Next. Run Next's own recommended\nagent workflow, which bumps Next + React and migrates the code as one unit:\n<https://nextjs.org/docs/app/guides/upgrading/version-16#use-an-ai-agent-recommended>\n\nIn short: run \\`npx @next/codemod@canary upgrade latest\\`, then\n\\`npx @next/codemod@canary next-async-request-api .\\`, and follow Next's AGENTS.md workflow for\nthe rest. Keep the result within the Next target range printed in step 2's report. Reinstall\nafterward so the \\`@payloadcms/next\\` peer resolves.\n\n## 4. Regenerate generated files\n\\`payload generate:types && payload generate:importmap\\`. Never hand-edit \\`payload-types.ts\\` or\n\\`importMap.js\\`; regenerate them.\n\n## 5. Fix-forward judgment work (against the now-v4 tree)\nThese depend on the v4 APIs and types existing, so they follow the upgrade. Open the bundled\nmigration guide (\\`v4.mdx\\`, path printed in step 2) and the bundled runbook\n(\\`runbook/payload-v4-upgrade.md\\`) and work the items they list: SCSS -> CSS and \\`--theme-*\\` ->\n\\`--color-*\\` token renames, Lexical union type-narrowing, jobs DB migrations, strict cron parsing,\nand anything flagged in the per-transform notes. Consult the guide for each; do not guess from\nmemory.\n\n## 6. Verify\n- \\`tsc --noEmit\\` (delete \\`tsconfig.tsbuildinfo\\` first; set \\`checkJs: true\\` so \\`importMap.js\\` is covered).\n- Run integration and e2e tests separately.\n- Build.\n- Confirm native modules (e.g. \\`sharp\\`) still load.\n\n## 7. Report\nDistinguish verified, cannot-confirm, and broken. Do not call the upgrade complete while any\ngate fails or any generated file is stale.\n`\n}\n"],"names":["renderUpgradePrompt","command"],"mappings":"AAAA;;;;;;;;;CASC,GACD,OAAO,SAASA,oBAAoB,EAClCC,UAAU,yBAAyB,EACd,GAAG,CAAC,CAAC;IAC1B,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;IAoBN,EAAEA,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2Cd,CAAC;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rewritePackageJson.d.ts","sourceRoot":"","sources":["../../src/upgrade/rewritePackageJson.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rewritePackageJson.d.ts","sourceRoot":"","sources":["../../src/upgrade/rewritePackageJson.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,QAAQ,EAAE,gBAAgB,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,mBAAmB,EAAE,MAAM,EAAE,CAAA;CAC9B,CAAA;AAOD,eAAO,MAAM,gBAAgB,SAAU,MAAM,KAAG,OACO,CAAA;AAEvD;;;GAGG;AACH,eAAO,MAAM,sBAAsB,SAAU,MAAM,KAAG,OACf,CAAA;AAEvC;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,SAAU,OAAO,KAAG,OACO,CAAA;AAEzD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,WAAW,GAAG,cAAc,CAKlF"}
|