@lowdefy/codemods 0.0.0-experimental-20260318092212

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.
@@ -0,0 +1,127 @@
1
+ # Migration: Simple Property and Event Renames
2
+
3
+ ## Context
4
+
5
+ Several blocks have properties and events renamed in antd v6. These are direct renames with no value changes (except where noted).
6
+
7
+ ## What to Do
8
+
9
+ Apply these renames in all YAML files:
10
+
11
+ | Block | Old Name | New Name | Type |
12
+ | -------- | -------------------- | --------------------- | -------- |
13
+ | Modal | `visible` | `open` | Property |
14
+ | Tooltip | `defaultVisible` | `defaultOpen` | Property |
15
+ | Tooltip | `onVisibleChange` | `onOpenChange` | Event |
16
+ | Progress | `gapPosition` | `gapPlacement` | Property |
17
+ | Carousel | `dotPosition` | `dotPlacement` | Property |
18
+ | Collapse | `expandIconPosition` | `expandIconPlacement` | Property |
19
+
20
+ ### Special handling for Modal `visible`
21
+
22
+ The `visible` key is also used at the block level (all blocks have a `visible:` property for conditional rendering). Only rename `visible` that is inside a Modal block's `properties:` section — not the block-level `visible:`.
23
+
24
+ **How to distinguish:**
25
+
26
+ - Block-level `visible:` is at the same indent as `type:`, `properties:`, `events:`
27
+ - Properties-level `visible:` is nested under `properties:` (indented 2 more spaces)
28
+ - Only rename when the block's `type:` is `Modal`
29
+
30
+ ## Files to Check
31
+
32
+ Glob: `**/*.{yaml,yml}`
33
+ Grep: `visible:|defaultVisible:|onVisibleChange:|gapPosition:|dotPosition:|expandIconPosition:`
34
+
35
+ ## Examples
36
+
37
+ ### Before — Modal visible
38
+
39
+ ```yaml
40
+ - id: my_modal
41
+ type: Modal
42
+ properties:
43
+ title: Confirm
44
+ visible:
45
+ _state: showModal
46
+ ```
47
+
48
+ ### After
49
+
50
+ ```yaml
51
+ - id: my_modal
52
+ type: Modal
53
+ properties:
54
+ title: Confirm
55
+ open:
56
+ _state: showModal
57
+ ```
58
+
59
+ ### Before — Tooltip event
60
+
61
+ ```yaml
62
+ - id: info_tooltip
63
+ type: Tooltip
64
+ properties:
65
+ defaultVisible: true
66
+ events:
67
+ onVisibleChange:
68
+ try:
69
+ - id: log
70
+ type: SetState
71
+ ```
72
+
73
+ ### After
74
+
75
+ ```yaml
76
+ - id: info_tooltip
77
+ type: Tooltip
78
+ properties:
79
+ defaultOpen: true
80
+ events:
81
+ onOpenChange:
82
+ try:
83
+ - id: log
84
+ type: SetState
85
+ ```
86
+
87
+ ### Before — Progress and Carousel
88
+
89
+ ```yaml
90
+ - id: progress1
91
+ type: Progress
92
+ properties:
93
+ gapPosition: bottom
94
+
95
+ - id: carousel1
96
+ type: Carousel
97
+ properties:
98
+ dotPosition: left
99
+ ```
100
+
101
+ ### After
102
+
103
+ ```yaml
104
+ - id: progress1
105
+ type: Progress
106
+ properties:
107
+ gapPlacement: bottom
108
+
109
+ - id: carousel1
110
+ type: Carousel
111
+ properties:
112
+ dotPlacement: left
113
+ ```
114
+
115
+ ## Edge Cases
116
+
117
+ - `defaultVisible`, `gapPosition`, `dotPosition`, `expandIconPosition`, `onVisibleChange` are unique property names — safe to rename globally without block-type checking
118
+ - `visible` is NOT unique — it exists on all blocks. Only rename under Modal's `properties:` section
119
+ - Do not rename inside code blocks, string values, or operator key paths
120
+
121
+ ## Verification
122
+
123
+ ```
124
+ grep -rn 'defaultVisible:\|gapPosition:\|dotPosition:\|expandIconPosition:\|onVisibleChange:' --include='*.yaml' --include='*.yml' .
125
+ ```
126
+
127
+ Should return zero matches. Then manually verify Modal `visible` → `open` was applied correctly.
@@ -0,0 +1,85 @@
1
+ # Migration: Tabs `tabPosition` → `tabPlacement` with Value Mapping
2
+
3
+ ## Context
4
+
5
+ The Tabs block renames `tabPosition` to `tabPlacement` and remaps directional values from physical to logical names.
6
+
7
+ ## What to Do
8
+
9
+ 1. Rename `tabPosition` to `tabPlacement`
10
+ 2. Map values: `left` → `start`, `right` → `end`
11
+ 3. `top` and `bottom` are unchanged
12
+
13
+ ## Files to Check
14
+
15
+ Glob: `**/*.{yaml,yml}`
16
+ Grep: `tabPosition:`
17
+
18
+ ## Examples
19
+
20
+ ### Before
21
+
22
+ ```yaml
23
+ - id: settings_tabs
24
+ type: Tabs
25
+ properties:
26
+ tabPosition: left
27
+ ```
28
+
29
+ ### After
30
+
31
+ ```yaml
32
+ - id: settings_tabs
33
+ type: Tabs
34
+ properties:
35
+ tabPlacement: start
36
+ ```
37
+
38
+ ### Before — right position
39
+
40
+ ```yaml
41
+ - id: nav_tabs
42
+ type: Tabs
43
+ properties:
44
+ tabPosition: right
45
+ ```
46
+
47
+ ### After
48
+
49
+ ```yaml
50
+ - id: nav_tabs
51
+ type: Tabs
52
+ properties:
53
+ tabPlacement: end
54
+ ```
55
+
56
+ ### Before — top (no value change)
57
+
58
+ ```yaml
59
+ - id: main_tabs
60
+ type: Tabs
61
+ properties:
62
+ tabPosition: top
63
+ ```
64
+
65
+ ### After
66
+
67
+ ```yaml
68
+ - id: main_tabs
69
+ type: Tabs
70
+ properties:
71
+ tabPlacement: top
72
+ ```
73
+
74
+ ## Edge Cases
75
+
76
+ - If the value is an operator expression (e.g., `tabPosition: { _state: position }`), rename the key to `tabPlacement` but flag for manual review — the state value may contain `"left"` or `"right"` that also needs updating
77
+ - `tabPosition` is a unique property name — safe to rename globally without block-type checking
78
+
79
+ ## Verification
80
+
81
+ ```
82
+ grep -rn 'tabPosition:' --include='*.yaml' --include='*.yml' .
83
+ ```
84
+
85
+ Should return zero matches.
@@ -0,0 +1,83 @@
1
+ # Migration: Notification `message` → `title`
2
+
3
+ ## Context
4
+
5
+ The Notification block renames its `message` property to `title` in antd v6. This is a context-aware rename — `message` is a common word that appears in many contexts, so only rename it inside Notification block properties.
6
+
7
+ ## What to Do
8
+
9
+ Find Notification blocks and rename `message:` to `title:` within their `properties:` section only.
10
+
11
+ ## Files to Check
12
+
13
+ Glob: `**/*.{yaml,yml}`
14
+ Grep: `type: Notification` (to find Notification blocks, then check for `message:` inside their properties)
15
+
16
+ ## Examples
17
+
18
+ ### Before
19
+
20
+ ```yaml
21
+ - id: success_notify
22
+ type: Notification
23
+ properties:
24
+ message: Record saved
25
+ description: Your changes have been saved successfully.
26
+ type: success
27
+ ```
28
+
29
+ ### After
30
+
31
+ ```yaml
32
+ - id: success_notify
33
+ type: Notification
34
+ properties:
35
+ title: Record saved
36
+ description: Your changes have been saved successfully.
37
+ type: success
38
+ ```
39
+
40
+ ### Before — with operator expression
41
+
42
+ ```yaml
43
+ - id: error_notify
44
+ type: Notification
45
+ properties:
46
+ message:
47
+ _string.concat:
48
+ - 'Error: '
49
+ - _state: errorMessage
50
+ type: error
51
+ ```
52
+
53
+ ### After
54
+
55
+ ```yaml
56
+ - id: error_notify
57
+ type: Notification
58
+ properties:
59
+ title:
60
+ _string.concat:
61
+ - 'Error: '
62
+ - _state: errorMessage
63
+ type: error
64
+ ```
65
+
66
+ ## Edge Cases
67
+
68
+ - **Only rename `message` inside Notification block properties.** Do not rename `message` in:
69
+ - DisplayMessage action params (different context)
70
+ - Other block properties (e.g., Alert has its own `message`)
71
+ - State values or operator expressions
72
+ - To identify context: find `type: Notification` at block level, then look for `properties:` at the next indent, then look for `message:` as a direct child of properties
73
+ - Notification can appear as both a block and an action — only rename in block properties, not in action params
74
+
75
+ ## Verification
76
+
77
+ Search for Notification blocks and verify none still have `message:` under properties:
78
+
79
+ ```
80
+ grep -rn 'type: Notification' --include='*.yaml' --include='*.yml' . -A 10 | grep 'message:'
81
+ ```
82
+
83
+ Should return zero matches.
@@ -0,0 +1,108 @@
1
+ # Migration: Divider Dual Rename — `type`/`orientation` Swap
2
+
3
+ ## Context
4
+
5
+ The Divider block has a dual rename where both `type` and `orientation` change meaning:
6
+
7
+ - Old `type` (direction: horizontal/vertical) → becomes `orientation`
8
+ - Old `orientation` (text position: left/center/right) → becomes `titlePlacement` with value mapping
9
+
10
+ This is tricky because both properties exist and their meanings swap. A naive rename would break the config.
11
+
12
+ ## What to Do
13
+
14
+ For each Divider block, apply both renames simultaneously:
15
+
16
+ | Old Property | Old Values | New Property | New Values |
17
+ | --------------------- | -------------------- | ------------------------- | -------------------- |
18
+ | `type: horizontal` | horizontal, vertical | `orientation: horizontal` | horizontal, vertical |
19
+ | `type: vertical` | | `orientation: vertical` | |
20
+ | `orientation: left` | left, center, right | `titlePlacement: start` | start, center, end |
21
+ | `orientation: center` | | `titlePlacement: center` | |
22
+ | `orientation: right` | | `titlePlacement: end` | |
23
+
24
+ **Important:** Apply both changes in one pass to avoid the intermediate state where `type` is renamed to `orientation` and then conflicts with the existing `orientation`.
25
+
26
+ ## Files to Check
27
+
28
+ Glob: `**/*.{yaml,yml}`
29
+ Grep: `type: Divider`
30
+
31
+ ## Examples
32
+
33
+ ### Before — horizontal divider with left text
34
+
35
+ ```yaml
36
+ - id: section_divider
37
+ type: Divider
38
+ properties:
39
+ type: horizontal
40
+ orientation: left
41
+ children: Section Title
42
+ ```
43
+
44
+ ### After
45
+
46
+ ```yaml
47
+ - id: section_divider
48
+ type: Divider
49
+ properties:
50
+ orientation: horizontal
51
+ titlePlacement: start
52
+ children: Section Title
53
+ ```
54
+
55
+ ### Before — vertical divider (no orientation)
56
+
57
+ ```yaml
58
+ - id: vert_divider
59
+ type: Divider
60
+ properties:
61
+ type: vertical
62
+ ```
63
+
64
+ ### After
65
+
66
+ ```yaml
67
+ - id: vert_divider
68
+ type: Divider
69
+ properties:
70
+ orientation: vertical
71
+ ```
72
+
73
+ ### Before — only orientation set
74
+
75
+ ```yaml
76
+ - id: centered_divider
77
+ type: Divider
78
+ properties:
79
+ orientation: center
80
+ children: OR
81
+ ```
82
+
83
+ ### After
84
+
85
+ ```yaml
86
+ - id: centered_divider
87
+ type: Divider
88
+ properties:
89
+ titlePlacement: center
90
+ children: OR
91
+ ```
92
+
93
+ ## Edge Cases
94
+
95
+ - A Divider may have only `type`, only `orientation`, or both — handle each case
96
+ - `type:` on a Divider is NOT the block-level `type:` key (which identifies the component). The block-level `type: Divider` stays unchanged. Only rename `type:` that is under `properties:`
97
+ - If `type` or `orientation` use operator expressions, rename the key but flag the value for manual review
98
+ - Verify each Divider after transformation — the dual swap is error-prone
99
+
100
+ ## Verification
101
+
102
+ Search for Divider blocks and check for old property names:
103
+
104
+ ```
105
+ grep -rn 'type: Divider' --include='*.yaml' --include='*.yml' . -A 10 | grep -E '^\s+(type|orientation):'
106
+ ```
107
+
108
+ Under Divider properties, `type:` should not appear (replaced by `orientation:`), and `orientation:` with values `left`/`right` should not appear (replaced by `titlePlacement:`).
@@ -0,0 +1,131 @@
1
+ # Migration: Button `type`/`danger` → `color` + `variant`
2
+
3
+ ## Context
4
+
5
+ The Button block replaces the combined `type` and `danger` properties with separate `color` and `variant` properties in antd v6. The `type` property previously controlled both visual style and color in a single enum. Now these concerns are split.
6
+
7
+ ## What to Do
8
+
9
+ For each Button block, replace `type` and `danger` with the equivalent `color` and `variant` combination:
10
+
11
+ | Old `type` | Old `danger` | New `color` | New `variant` |
12
+ | -------------------- | ------------ | ----------- | ------------- |
13
+ | `primary` | — | `primary` | `solid` |
14
+ | `primary` | `true` | `danger` | `solid` |
15
+ | `default` or omitted | — | _(omit)_ | _(omit)_ |
16
+ | `default` or omitted | `true` | `danger` | _(omit)_ |
17
+ | `dashed` | — | _(omit)_ | `dashed` |
18
+ | `dashed` | `true` | `danger` | `dashed` |
19
+ | `text` | — | _(omit)_ | `text` |
20
+ | `text` | `true` | `danger` | `text` |
21
+ | `link` | — | _(omit)_ | `link` |
22
+ | `link` | `true` | `danger` | `link` |
23
+
24
+ Remove both old properties (`type` under Button properties, and `danger`) and add the new `color` and `variant` properties.
25
+
26
+ ## Files to Check
27
+
28
+ Glob: `**/*.{yaml,yml}`
29
+ Grep: `type: Button`
30
+
31
+ ## Examples
32
+
33
+ ### Before — primary button
34
+
35
+ ```yaml
36
+ - id: submit_btn
37
+ type: Button
38
+ properties:
39
+ title: Submit
40
+ type: primary
41
+ ```
42
+
43
+ ### After
44
+
45
+ ```yaml
46
+ - id: submit_btn
47
+ type: Button
48
+ properties:
49
+ title: Submit
50
+ color: primary
51
+ variant: solid
52
+ ```
53
+
54
+ ### Before — danger button
55
+
56
+ ```yaml
57
+ - id: delete_btn
58
+ type: Button
59
+ properties:
60
+ title: Delete
61
+ type: primary
62
+ danger: true
63
+ ```
64
+
65
+ ### After
66
+
67
+ ```yaml
68
+ - id: delete_btn
69
+ type: Button
70
+ properties:
71
+ title: Delete
72
+ color: danger
73
+ variant: solid
74
+ ```
75
+
76
+ ### Before — link button
77
+
78
+ ```yaml
79
+ - id: cancel_btn
80
+ type: Button
81
+ properties:
82
+ title: Cancel
83
+ type: link
84
+ ```
85
+
86
+ ### After
87
+
88
+ ```yaml
89
+ - id: cancel_btn
90
+ type: Button
91
+ properties:
92
+ title: Cancel
93
+ variant: link
94
+ ```
95
+
96
+ ### Before — default button with danger
97
+
98
+ ```yaml
99
+ - id: remove_btn
100
+ type: Button
101
+ properties:
102
+ title: Remove
103
+ danger: true
104
+ ```
105
+
106
+ ### After
107
+
108
+ ```yaml
109
+ - id: remove_btn
110
+ type: Button
111
+ properties:
112
+ title: Remove
113
+ color: danger
114
+ ```
115
+
116
+ ## Edge Cases
117
+
118
+ - **`type:` under Button properties is NOT the block-level `type: Button`.** Only rename `type:` that is a child of the Button's `properties:` section
119
+ - If `type` uses an operator expression (e.g., `type: { _if: ... }`), flag for manual review — the expression logic needs updating to return `color`/`variant` pairs instead
120
+ - `danger: true` can appear with or without `type` — handle both cases
121
+ - `danger: false` can be removed entirely (it's the default)
122
+ - If a Button has `type: default` explicitly, just remove it (default is the default)
123
+ - Visual differences are possible — `type: primary` had built-in hover effects that `color: primary, variant: solid` reproduces, but custom CSS may need adjustment
124
+
125
+ ## Verification
126
+
127
+ ```
128
+ grep -rn 'type: Button' --include='*.yaml' --include='*.yml' . -A 10 | grep -E '^\s+(type:|danger:)'
129
+ ```
130
+
131
+ No `type:` or `danger:` should appear under Button properties after migration (except operator-expression cases flagged for review).
@@ -0,0 +1,105 @@
1
+ # Migration: `public/styles.less` → Theme YAML + CSS
2
+
3
+ ## Context
4
+
5
+ Lowdefy v4 supported `public/styles.less` for custom styling with Less variables that mapped to antd's Less-based theming. Antd v6 uses CSS-in-JS with design tokens. Less is no longer processed by the build.
6
+
7
+ ## What to Do
8
+
9
+ 1. Check if `public/styles.less` exists
10
+ 2. If it does, parse its content and split into two buckets:
11
+ - **Less variables** → map to antd design tokens in `lowdefy.yaml` theme config
12
+ - **Plain CSS / complex Less** → convert to `public/styles.css`
13
+
14
+ ### Known Less Variable → Token Mapping
15
+
16
+ | Less Variable | Antd Token |
17
+ | ----------------------- | -------------------- |
18
+ | `@primary-color` | `colorPrimary` |
19
+ | `@link-color` | `colorLink` |
20
+ | `@success-color` | `colorSuccess` |
21
+ | `@warning-color` | `colorWarning` |
22
+ | `@error-color` | `colorError` |
23
+ | `@font-size-base` | `fontSize` |
24
+ | `@heading-color` | `colorTextHeading` |
25
+ | `@text-color` | `colorText` |
26
+ | `@text-color-secondary` | `colorTextSecondary` |
27
+ | `@disabled-color` | `colorTextDisabled` |
28
+ | `@border-radius-base` | `borderRadius` |
29
+ | `@border-color-base` | `colorBorder` |
30
+ | `@box-shadow-base` | `boxShadow` |
31
+ | `@body-background` | `colorBgContainer` |
32
+
33
+ For each variable found, generate the equivalent `theme.antd.token` YAML:
34
+
35
+ ```yaml
36
+ # Add to lowdefy.yaml
37
+ theme:
38
+ antd:
39
+ token:
40
+ colorPrimary: '#1890ff'
41
+ fontSize: 14
42
+ borderRadius: 4
43
+ ```
44
+
45
+ ### Complex Less (manual conversion needed)
46
+
47
+ Flag these for manual conversion:
48
+
49
+ - Less mixins (`.mixin()`)
50
+ - Less functions (`darken()`, `lighten()`, `fade()`)
51
+ - Nested selectors with `&`
52
+ - `@import` statements (other than antd imports)
53
+ - Any Less-specific syntax
54
+
55
+ Convert remaining plain CSS to `public/styles.css`.
56
+
57
+ ## Files to Check
58
+
59
+ Check: `public/styles.less`
60
+
61
+ ## Examples
62
+
63
+ ### Before — styles.less
64
+
65
+ ```less
66
+ @primary-color: #1890ff;
67
+ @border-radius-base: 6px;
68
+ @font-size-base: 14px;
69
+
70
+ .custom-header {
71
+ padding: 16px;
72
+ background: @primary-color;
73
+ }
74
+ ```
75
+
76
+ ### After — lowdefy.yaml addition
77
+
78
+ ```yaml
79
+ theme:
80
+ antd:
81
+ token:
82
+ colorPrimary: '#1890ff'
83
+ borderRadius: 6
84
+ fontSize: 14
85
+ ```
86
+
87
+ ### After — public/styles.css (for non-variable CSS)
88
+
89
+ ```css
90
+ .custom-header {
91
+ padding: 16px;
92
+ background: var(--ant-color-primary);
93
+ }
94
+ ```
95
+
96
+ ## Edge Cases
97
+
98
+ - If `styles.less` contains only variables and no custom CSS, only the `lowdefy.yaml` theme config is needed — no `styles.css`
99
+ - Less expressions like `darken(@primary-color, 10%)` have no direct token equivalent — flag these for manual conversion to CSS custom properties or hardcoded values
100
+ - Some apps may import antd Less files (`@import '~antd/dist/antd.less'`) — these lines can be removed entirely (antd v6 doesn't use Less)
101
+ - If `lowdefy.yaml` already has a `theme:` section, merge the tokens into it
102
+
103
+ ## Verification
104
+
105
+ After migration, `public/styles.less` should be renamed or deleted. The app should build without Less processing errors.
@@ -0,0 +1,78 @@
1
+ # Migration: Detect Custom Date Format Strings
2
+
3
+ ## Context
4
+
5
+ The date blocks use dayjs instead of moment.js in antd v6. Most format strings are compatible, but edge cases exist with locale-specific tokens and some moment-specific patterns.
6
+
7
+ ## What to Do
8
+
9
+ Find custom date format strings on date blocks and verify they work with dayjs. Standard formats need no changes.
10
+
11
+ **Affected blocks:** DateSelector, DateRangeSelector, DateTimeSelector, MonthSelector, WeekSelector.
12
+
13
+ **Standard formats (no action needed):**
14
+
15
+ - `YYYY-MM-DD`
16
+ - `YYYY-MM-DD HH:mm:ss`
17
+ - `YYYY-MM-DD HH:mm`
18
+ - `HH:mm:ss`
19
+ - `HH:mm`
20
+
21
+ **Formats to check:**
22
+
23
+ - Custom format strings that aren't in the standard list above
24
+ - Locale-specific format tokens (e.g., `LLLL`, `LT`, `LTS`)
25
+ - Moment-specific tokens: `Mo` (ordinal month), `Do` (ordinal day), `Qo` (ordinal quarter)
26
+
27
+ ## Files to Check
28
+
29
+ Glob: `**/*.{yaml,yml}`
30
+ Grep: `type: DateSelector|type: DateRangeSelector|type: DateTimeSelector|type: MonthSelector|type: WeekSelector`
31
+
32
+ Then look for `format:` properties within those blocks.
33
+
34
+ ## Examples
35
+
36
+ ### No action needed
37
+
38
+ ```yaml
39
+ - id: start_date
40
+ type: DateSelector
41
+ properties:
42
+ format: YYYY-MM-DD
43
+ ```
44
+
45
+ ### Needs review
46
+
47
+ ```yaml
48
+ - id: display_date
49
+ type: DateSelector
50
+ properties:
51
+ format: Do MMMM YYYY
52
+ ```
53
+
54
+ `Do` (ordinal day like "1st", "2nd") requires the dayjs `advancedFormat` plugin. Verify it renders correctly.
55
+
56
+ ### Operator expression — skip
57
+
58
+ ```yaml
59
+ - id: dynamic_date
60
+ type: DateSelector
61
+ properties:
62
+ format:
63
+ _state: dateFormat
64
+ ```
65
+
66
+ Skip operator expressions — they'll resolve at runtime.
67
+
68
+ ## Edge Cases
69
+
70
+ - This is a **report-only** migration — don't change format strings automatically
71
+ - Most moment format tokens work identically in dayjs
72
+ - The `Do`, `Mo`, `Qo` ordinal tokens require dayjs's `advancedFormat` plugin (bundled by Lowdefy)
73
+ - `X` (unix timestamp) and `x` (millisecond timestamp) work in both
74
+ - Locale-dependent formats (`L`, `LL`, `LLL`, `LLLL`, `LT`, `LTS`) work but may produce slightly different output depending on locale data differences between moment and dayjs
75
+
76
+ ## Verification
77
+
78
+ This is informational — no files should change. The user should test date rendering in their app after the upgrade.