@pantheon-systems/pds-design-tokens 2.0.0-alpha.55 → 2.0.0-alpha.56

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.
@@ -73,7 +73,6 @@
73
73
  --pds-spacing-button-gap-inline-l: var(--pds-spacing-xs);
74
74
  --pds-spacing-input-height-s: var(--pds-spacing-2xl);
75
75
  --pds-spacing-input-height-m: var(--pds-spacing-3xl);
76
- --pds-spacing-input-height-l: var(--pds-spacing-4xl);
77
76
  --pds-z-index-navigation: 100;
78
77
  --pds-z-index-dropdown: 300;
79
78
  --pds-z-index-notifications: 500;
@@ -896,23 +896,6 @@
896
896
  }
897
897
  }
898
898
  }
899
- },
900
- "l": {
901
- "value": "{spacing.4XL}",
902
- "type": "dimension",
903
- "$extensions": {
904
- "public": true,
905
- "defaultUnit": "rem",
906
- "com.figma": {
907
- "scopes": [
908
- "WIDTH_HEIGHT"
909
- ],
910
- "exportAs": "variable",
911
- "codeSyntax": {
912
- "WEB": "--pds-spacing-input-height-l"
913
- }
914
- }
915
- }
916
899
  }
917
900
  }
918
901
  }
@@ -80,7 +80,6 @@ export const SPACING_BUTTON_GAP_INLINE_M: string;
80
80
  export const SPACING_BUTTON_GAP_INLINE_L: string;
81
81
  export const SPACING_INPUT_HEIGHT_S: string;
82
82
  export const SPACING_INPUT_HEIGHT_M: string;
83
- export const SPACING_INPUT_HEIGHT_L: string;
84
83
  export const TYPOGRAPHY_FONT_CSS_IMPORT: string;
85
84
  export const Z_INDEX_NAVIGATION: number;
86
85
  export const Z_INDEX_DROPDOWN: number;
@@ -80,7 +80,6 @@ export const SPACING_BUTTON_GAP_INLINE_M = "0.625rem";
80
80
  export const SPACING_BUTTON_GAP_INLINE_L = "0.625rem";
81
81
  export const SPACING_INPUT_HEIGHT_S = "2rem";
82
82
  export const SPACING_INPUT_HEIGHT_M = "2.5rem";
83
- export const SPACING_INPUT_HEIGHT_L = "3rem";
84
83
  export const TYPOGRAPHY_FONT_CSS_IMPORT = "'https://fonts.googleapis.com/css2?family=IBM+Plex+Serif:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=Inter+Tight:ital,wght@0,100..900;1,100..900&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap'";
85
84
  export const Z_INDEX_NAVIGATION = 100;
86
85
  export const Z_INDEX_DROPDOWN = 300;
@@ -1715,29 +1715,6 @@
1715
1715
  "m"
1716
1716
  ],
1717
1717
  "public": true
1718
- },
1719
- "l": {
1720
- "value": "3",
1721
- "filePath": "tokens/spacing/semantic/input.json",
1722
- "isSource": true,
1723
- "original": {
1724
- "value": "{spacing.4XL}",
1725
- "public": true
1726
- },
1727
- "name": "SpacingInputHeightL",
1728
- "attributes": {
1729
- "category": "spacing",
1730
- "type": "input",
1731
- "item": "height",
1732
- "subitem": "l"
1733
- },
1734
- "path": [
1735
- "spacing",
1736
- "input",
1737
- "height",
1738
- "l"
1739
- ],
1740
- "public": true
1741
1718
  }
1742
1719
  }
1743
1720
  }
@@ -0,0 +1,203 @@
1
+ # v1 to v2 Migration Codemod
2
+
3
+ This directory contains the data and tooling for the automated migration from v1.x to v2.x of PDS Design Tokens.
4
+
5
+ **Status:** šŸ“ Data collection phase (Alpha)
6
+
7
+ The codemod itself will be built during the beta phase when the API is frozen.
8
+
9
+ ## Contents
10
+
11
+ ### `mappings.json`
12
+
13
+ **Purpose:** Machine-readable source of truth for all breaking changes
14
+
15
+ This file tracks:
16
+ - File path renames (CSS, JS)
17
+ - Token renames (direct 1:1 mappings)
18
+ - Token patterns (wildcards like `--pds-color-gradient-avatar-*`)
19
+ - Token removals (with optional replacement notes)
20
+ - Value format changes (e.g., decimal → percentage)
21
+ - Categories for grouping related changes
22
+
23
+ **When to update:**
24
+ - Every time you make a breaking change during alpha/beta
25
+ - Update this file FIRST, then auto-generate the migration guide
26
+ - This ensures consistency and makes codemod development easier
27
+
28
+ ### `validate.js`
29
+
30
+ **Purpose:** Validates `mappings.json` for consistency
31
+
32
+ Checks for:
33
+ - Valid JSON structure
34
+ - No duplicate "from" tokens
35
+ - No duplicate removals
36
+ - All category references exist
37
+ - No conflicts (token in both renames and removals)
38
+
39
+ **Usage:**
40
+ ```bash
41
+ # Direct
42
+ node codemods/v1-to-v2/validate.js
43
+
44
+ # Or via npm script
45
+ npm run validate:mappings
46
+ ```
47
+
48
+ Run this before committing changes to ensure data integrity.
49
+
50
+ ### `generate-migration-guide.js`
51
+
52
+ **Purpose:** Auto-generates the Breaking Changes section of `guides/MIGRATION-v2.md` from `mappings.json`
53
+
54
+ Generates:
55
+ - Summary-style Breaking Changes with counts and categories
56
+ - Links to detailed Step-by-Step Migration sections
57
+ - Organized by: File Structure, Token Removals, Token Renames, Category Changes, Format Changes, New Features
58
+
59
+ **Usage:**
60
+ ```bash
61
+ # Direct
62
+ node codemods/v1-to-v2/generate-migration-guide.js
63
+
64
+ # Or via npm script
65
+ npm run generate:migration
66
+ ```
67
+
68
+ Run this after updating `mappings.json` to keep the migration guide in sync.
69
+
70
+ ## Workflow for Adding Breaking Changes
71
+
72
+ When you make a breaking change during alpha/beta:
73
+
74
+ ### 1. Update `mappings.json`
75
+
76
+ **For a token rename:**
77
+ ```json
78
+ {
79
+ "from": "--pds-old-token",
80
+ "to": "--pds-new-token",
81
+ "category": "animation"
82
+ }
83
+ ```
84
+
85
+ Add to `tokens.renames` array.
86
+
87
+ **For a token removal:**
88
+ ```json
89
+ {
90
+ "token": "--pds-removed-token",
91
+ "category": "color",
92
+ "replacement": null,
93
+ "note": "Optional note about why it was removed"
94
+ }
95
+ ```
96
+
97
+ Add to `tokens.removals` array.
98
+
99
+ **For a file rename:**
100
+ ```json
101
+ {
102
+ "from": "build/css/old-file.css",
103
+ "to": "build/css/new-file.css",
104
+ "description": "Brief description"
105
+ }
106
+ ```
107
+
108
+ Add to `files.renames` array.
109
+
110
+ ### 2. Validate the changes
111
+
112
+ ```bash
113
+ npm run validate:mappings
114
+ ```
115
+
116
+ ### 3. Generate migration guide
117
+
118
+ ```bash
119
+ npm run generate:migration
120
+ ```
121
+
122
+ This auto-generates a summary-style Breaking Changes section in `guides/MIGRATION-v2.md` from `mappings.json`. The summary includes counts, categories, and links to detailed step-by-step instructions.
123
+
124
+ ### 4. Update CHANGELOG
125
+
126
+ Add entry to `CHANGELOG.mdx` with "BREAKING:" prefix.
127
+
128
+ ### 5. Commit together
129
+
130
+ ```bash
131
+ git add tokens/ codemods/v1-to-v2/mappings.json guides/MIGRATION-v2.md CHANGELOG.mdx
132
+ git commit -m "BREAKING: Description
133
+
134
+ - Specific change
135
+ - Updated mappings.json and auto-generated migration guide"
136
+ ```
137
+
138
+ ## Future: Codemod Implementation
139
+
140
+ **Timeline:** Build during beta phase (when API is frozen)
141
+
142
+ **Implementation plan:**
143
+ - Use [jscodeshift](https://github.com/facebook/jscodeshift) for JS/TS transformations
144
+ - Use [postcss](https://postcss.org/) for CSS/SCSS transformations
145
+ - Read from `mappings.json` for all transformation rules
146
+ - Provide dry-run mode to preview changes
147
+ - Generate report of:
148
+ - Automated changes (file renames, token renames)
149
+ - Manual review needed (removed tokens, value changes)
150
+
151
+ **Usage (future):**
152
+ ```bash
153
+ npx @pantheon-systems/pds-design-tokens migrate v1-to-v2
154
+ ```
155
+
156
+ ## Categories
157
+
158
+ Current categories defined in `mappings.json`:
159
+
160
+ - **animation** - Animation and transition tokens
161
+ - **status-colors** - Status color tokens (info, success, warning, critical, discovery)
162
+ - **text-colors** - Text and foreground color tokens
163
+ - **typography** - Typography tokens (font families, sizes, etc.)
164
+ - **gradients** - Gradient tokens (moved from color category)
165
+ - **border** - Border width and offset tokens
166
+ - **color** - General color tokens
167
+ - **component** - Component-specific tokens
168
+
169
+ Add new categories as needed to keep changes organized.
170
+
171
+ ## Validation Script Output
172
+
173
+ Example successful validation:
174
+
175
+ ```
176
+ āœ… mappings.json is valid JSON
177
+ āœ… No duplicate 'from' tokens in renames (19 unique)
178
+ āœ… No duplicate removal tokens (21 unique)
179
+ ā„¹ļø Valid categories: animation, status-colors, text-colors, typography, gradients, border, color, component
180
+ āœ… All token categories are valid
181
+ āœ… No conflicts between renames and removals
182
+
183
+ šŸ“Š Summary:
184
+ File renames: 3
185
+ Token renames: 19
186
+ Token patterns: 1
187
+ Token removals: 21
188
+ Value changes: 1
189
+ Categories: 8
190
+
191
+ āœ… All validations passed!
192
+ ```
193
+
194
+ ## Notes
195
+
196
+ - **Patterns:** Use `isPattern: true` for wildcard tokens like `--pds-color-gradient-avatar-*`
197
+ - **Removals:** Set `replacement: null` for tokens removed without direct replacement
198
+ - **Value changes:** Document transformation logic (e.g., "multiply by 100, add %")
199
+ - **Keep synced:** `mappings.json` is the source of truth - migration guide reflects this data
200
+
201
+ ---
202
+
203
+ For migration guide, see: `guides/MIGRATION-v2.md`
@@ -0,0 +1,384 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Generates the Breaking Changes section of MIGRATION-v2.md from mappings.json
5
+ *
6
+ * Usage: npm run generate:migration
7
+ *
8
+ * This script:
9
+ * 1. Reads codemods/v1-to-v2/mappings.json
10
+ * 2. Generates markdown for the Breaking Changes section
11
+ * 3. Updates guides/MIGRATION-v2.md between auto-generated markers
12
+ */
13
+
14
+ import { readFileSync, writeFileSync } from 'fs';
15
+ import { join, dirname } from 'path';
16
+ import { fileURLToPath } from 'url';
17
+
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = dirname(__filename);
20
+
21
+ const mappingsPath = join(__dirname, 'mappings.json');
22
+ const migrationGuidePath = join(__dirname, '../../guides/MIGRATION-v2.md');
23
+
24
+ // Load mappings.json
25
+ let mappings;
26
+ try {
27
+ const content = readFileSync(mappingsPath, 'utf8');
28
+ mappings = JSON.parse(content);
29
+ console.log('āœ… Loaded mappings.json');
30
+ } catch (error) {
31
+ console.error('āŒ Failed to load mappings.json:', error.message);
32
+ process.exit(1);
33
+ }
34
+
35
+ // Helper to get category name
36
+ const categoryMap = {};
37
+ if (mappings.categories) {
38
+ mappings.categories.forEach(cat => {
39
+ categoryMap[cat.id] = cat.name;
40
+ });
41
+ }
42
+
43
+ // Generate markdown sections - SUMMARY VERSION
44
+ function generateBreakingChanges() {
45
+ let markdown = '';
46
+
47
+ // File Structure Changes
48
+ if (mappings.files.renames && mappings.files.renames.length > 0) {
49
+ markdown += '### File Structure Changes\n\n';
50
+ markdown += `${mappings.files.renames.length} CSS files have been renamed with clearer naming:\n`;
51
+ markdown += '- `pds-design-tokens.css` → `variables.global.css`\n';
52
+ markdown += '- `pds-design-tokens-light-mode.css` → `variables.light.css`\n';
53
+ markdown += '- `pds-design-tokens-dark-mode.css` → `variables.dark.css`\n\n';
54
+ markdown += 'See [Step 2: Update CSS Imports](#step-2-update-css-imports) for details.\n\n';
55
+ }
56
+
57
+ // Token Removals
58
+ if (mappings.tokens.removals && mappings.tokens.removals.length > 0) {
59
+ const regularRemovals = mappings.tokens.removals.filter(r => !r.isPattern);
60
+ const patternRemovals = mappings.tokens.removals.filter(r => r.isPattern);
61
+
62
+ markdown += '### Token Removals\n\n';
63
+ markdown += `${regularRemovals.length} individual tokens and ${patternRemovals.length} token patterns have been removed:\n\n`;
64
+
65
+ // Group by category
66
+ const removalsByCategory = {};
67
+ regularRemovals.forEach(removal => {
68
+ const cat = removal.category || 'other';
69
+ if (!removalsByCategory[cat]) removalsByCategory[cat] = [];
70
+ removalsByCategory[cat].push(removal.token);
71
+ });
72
+
73
+ Object.keys(removalsByCategory).sort().forEach(categoryId => {
74
+ const categoryName = categoryMap[categoryId] || categoryId;
75
+ markdown += `- **${categoryName}**: ${removalsByCategory[categoryId].length} tokens\n`;
76
+ });
77
+
78
+ if (patternRemovals.length > 0) {
79
+ markdown += '\n**Patterns removed:**\n';
80
+ patternRemovals.forEach(removal => {
81
+ markdown += `- \`${removal.token}\``;
82
+ if (removal.note) {
83
+ markdown += ` (${removal.note})`;
84
+ }
85
+ markdown += '\n';
86
+ });
87
+ }
88
+
89
+ markdown += '\nSee [Step 4: Handle Removed Tokens](#step-4-handle-removed-tokens) for the complete list.\n\n';
90
+ }
91
+
92
+ // Token Renames
93
+ if (mappings.tokens.renames && mappings.tokens.renames.length > 0) {
94
+ markdown += '### Token Renames\n\n';
95
+ markdown += `${mappings.tokens.renames.length} tokens have been renamed for better consistency and clarity:\n\n`;
96
+
97
+ // Group by category
98
+ const byCategory = {};
99
+ mappings.tokens.renames.forEach(rename => {
100
+ const category = rename.category || 'other';
101
+ if (!byCategory[category]) {
102
+ byCategory[category] = [];
103
+ }
104
+ byCategory[category].push(rename);
105
+ });
106
+
107
+ // Output counts by category
108
+ Object.keys(byCategory).sort().forEach(categoryId => {
109
+ const categoryName = categoryMap[categoryId] || categoryId;
110
+ markdown += `- **${categoryName}**: ${byCategory[categoryId].length} tokens\n`;
111
+ });
112
+
113
+ markdown += '\nSee [Step 3: Update Token References](#step-3-update-token-references-direct-replacements) for the complete list with before/after mappings.\n\n';
114
+ }
115
+
116
+ // Token Patterns
117
+ if (mappings.tokens.patterns && mappings.tokens.patterns.length > 0) {
118
+ markdown += '### Category Changes\n\n';
119
+ mappings.tokens.patterns.forEach(pattern => {
120
+ const categoryName = pattern.category ? (categoryMap[pattern.category] || pattern.category) : 'Tokens';
121
+ markdown += `- **${categoryName}**: \`${pattern.from}\` → \`${pattern.to}\``;
122
+ if (pattern.description) {
123
+ markdown += ` (${pattern.description})`;
124
+ }
125
+ markdown += '\n';
126
+ });
127
+ markdown += '\n';
128
+ }
129
+
130
+ // Format Changes
131
+ if (mappings.tokens.valueChanges && mappings.tokens.valueChanges.length > 0) {
132
+ markdown += '### Format Changes\n\n';
133
+ mappings.tokens.valueChanges.forEach(change => {
134
+ markdown += `- **${change.property}**: Changed from ${change.from} to ${change.to}`;
135
+ if (change.transformation) {
136
+ markdown += ` (${change.transformation})`;
137
+ }
138
+ markdown += '\n';
139
+ });
140
+ markdown += '\nSee [Step 5: Update Letter Spacing Values](#step-5-update-letter-spacing-values) for details.\n\n';
141
+ }
142
+
143
+ // New Features
144
+ if (mappings.files.additions && mappings.files.additions.length > 0) {
145
+ markdown += '### New Features\n\n';
146
+ markdown += `${mappings.files.additions.length} new JavaScript constant files for importing tokens as ES6 modules.\n\n`;
147
+ markdown += 'See [Step 8: Optional - Use JS Constants](#step-8-optional---use-js-constants) for usage examples.\n\n';
148
+ }
149
+
150
+ // Notes
151
+ if (mappings.notes) {
152
+ Object.keys(mappings.notes).forEach(key => {
153
+ const note = mappings.notes[key];
154
+ if (note && note !== 'TBD' && !note.includes('TBD')) {
155
+ markdown += `**${key.replace(/-/g, ' ')}:**\n`;
156
+ markdown += `- ${note}\n\n`;
157
+ }
158
+ });
159
+ }
160
+
161
+ return markdown;
162
+ }
163
+
164
+ // Generate detailed token renames section for Step 3
165
+ function generateTokenRenames() {
166
+ let markdown = '';
167
+
168
+ if (!mappings.tokens.renames || mappings.tokens.renames.length === 0) {
169
+ return markdown;
170
+ }
171
+
172
+ // Group renames by category
173
+ const byCategory = {};
174
+ mappings.tokens.renames.forEach(rename => {
175
+ const category = rename.category || 'other';
176
+ if (!byCategory[category]) {
177
+ byCategory[category] = [];
178
+ }
179
+ byCategory[category].push(rename);
180
+ });
181
+
182
+ // Define category order and friendly names
183
+ const categoryOrder = [
184
+ 'status-colors',
185
+ 'text-colors',
186
+ 'typography',
187
+ 'animation',
188
+ 'border',
189
+ 'button',
190
+ 'container',
191
+ 'gradients',
192
+ 'other'
193
+ ];
194
+
195
+ // Generate markdown for each category
196
+ categoryOrder.forEach(categoryId => {
197
+ if (!byCategory[categoryId] || byCategory[categoryId].length === 0) {
198
+ return;
199
+ }
200
+
201
+ const categoryName = categoryMap[categoryId] || categoryId;
202
+ const renames = byCategory[categoryId];
203
+
204
+ markdown += `**${categoryName}:**\n\n`;
205
+ markdown += '```css\n';
206
+
207
+ // Add comment groups for status colors
208
+ if (categoryId === 'status-colors') {
209
+ const backgrounds = renames.filter(r => r.to.includes('-background'));
210
+ const icons = renames.filter(r => r.to.includes('-icon'));
211
+ const borders = renames.filter(r => r.to.includes('-border'));
212
+
213
+ if (backgrounds.length > 0) {
214
+ markdown += '/* Background colors */\n';
215
+ backgrounds.forEach(r => {
216
+ markdown += `${r.from.padEnd(30)} → ${r.to}\n`;
217
+ });
218
+ markdown += '\n';
219
+ }
220
+
221
+ if (icons.length > 0) {
222
+ markdown += '/* Icon/Foreground colors */\n';
223
+ icons.forEach(r => {
224
+ markdown += `${r.from.padEnd(30)} → ${r.to}\n`;
225
+ });
226
+ markdown += '\n';
227
+ }
228
+
229
+ if (borders.length > 0) {
230
+ markdown += '/* Border colors */\n';
231
+ borders.forEach(r => {
232
+ markdown += `${r.from.padEnd(30)} → ${r.to}\n`;
233
+ });
234
+ }
235
+ }
236
+ // Add comment groups for animation tokens
237
+ else if (categoryId === 'animation') {
238
+ const transitions = renames.filter(r =>
239
+ r.to.includes('-transition-') &&
240
+ !r.to.includes('-delay') &&
241
+ !r.to.includes('-duration') &&
242
+ !r.to.includes('-timing')
243
+ );
244
+ const properties = renames.filter(r =>
245
+ r.to.includes('-delay') ||
246
+ r.to.includes('-duration') ||
247
+ r.to.includes('-timing')
248
+ );
249
+
250
+ if (transitions.length > 0) {
251
+ markdown += '/* Transition tokens */\n';
252
+ transitions.forEach(r => {
253
+ markdown += `${r.from.padEnd(40)} → ${r.to}\n`;
254
+ });
255
+ markdown += '\n';
256
+ }
257
+
258
+ if (properties.length > 0) {
259
+ markdown += '/* Duration/delay/timing tokens */\n';
260
+ properties.forEach(r => {
261
+ markdown += `${r.from.padEnd(50)} → ${r.to}\n`;
262
+ });
263
+ }
264
+ }
265
+ // Simple list for other categories
266
+ else {
267
+ renames.forEach(r => {
268
+ const padding = categoryId === 'typography' ? 34 : 30;
269
+ markdown += `${r.from.padEnd(padding)} → ${r.to}\n`;
270
+ });
271
+ }
272
+
273
+ markdown += '```\n\n';
274
+ });
275
+
276
+ // Add pattern-based renames (like gradients)
277
+ if (mappings.tokens.patterns && mappings.tokens.patterns.length > 0) {
278
+ mappings.tokens.patterns.forEach(pattern => {
279
+ const categoryName = pattern.category ?
280
+ (categoryMap[pattern.category] || pattern.category) :
281
+ 'Pattern';
282
+
283
+ markdown += `**${categoryName}:**\n\n`;
284
+
285
+ if (pattern.description) {
286
+ markdown += `${pattern.description}:\n\n`;
287
+ }
288
+
289
+ markdown += '```css\n';
290
+ markdown += `${pattern.from} → ${pattern.to}\n`;
291
+
292
+ // Add example if it's a pattern
293
+ if (pattern.isPattern) {
294
+ markdown += '\n/* Example: */\n';
295
+ const exampleFrom = pattern.from.replace('*', 'midnight');
296
+ const exampleTo = pattern.to.replace('*', 'midnight');
297
+ markdown += `${exampleFrom} → ${exampleTo}\n`;
298
+ }
299
+
300
+ markdown += '```\n\n';
301
+ });
302
+ }
303
+
304
+ return markdown;
305
+ }
306
+
307
+ // Read current migration guide
308
+ let migrationContent;
309
+ try {
310
+ migrationContent = readFileSync(migrationGuidePath, 'utf8');
311
+ console.log('āœ… Loaded MIGRATION-v2.md');
312
+ } catch (error) {
313
+ console.error('āŒ Failed to load MIGRATION-v2.md:', error.message);
314
+ process.exit(1);
315
+ }
316
+
317
+ // Generate new sections
318
+ const newBreakingChanges = generateBreakingChanges();
319
+ const newTokenRenames = generateTokenRenames();
320
+
321
+ // Define markers for Breaking Changes section
322
+ const breakingStartMarker = '<!-- BEGIN AUTO-GENERATED BREAKING CHANGES -->';
323
+ const breakingEndMarker = '<!-- END AUTO-GENERATED BREAKING CHANGES -->';
324
+
325
+ // Define markers for Token Renames section
326
+ const renamesStartMarker = '<!-- BEGIN AUTO-GENERATED TOKEN RENAMES -->';
327
+ const renamesEndMarker = '<!-- END AUTO-GENERATED TOKEN RENAMES -->';
328
+
329
+ // Check if markers exist
330
+ if (!migrationContent.includes(breakingStartMarker) || !migrationContent.includes(breakingEndMarker)) {
331
+ console.error('āŒ Breaking Changes auto-generation markers not found in MIGRATION-v2.md');
332
+ console.error('Expected markers:');
333
+ console.error(' ' + breakingStartMarker);
334
+ console.error(' ' + breakingEndMarker);
335
+ console.error('\nPlease add these markers around the Breaking Changes section.');
336
+ process.exit(1);
337
+ }
338
+
339
+ if (!migrationContent.includes(renamesStartMarker) || !migrationContent.includes(renamesEndMarker)) {
340
+ console.error('āŒ Token Renames auto-generation markers not found in MIGRATION-v2.md');
341
+ console.error('Expected markers:');
342
+ console.error(' ' + renamesStartMarker);
343
+ console.error(' ' + renamesEndMarker);
344
+ console.error('\nPlease add these markers around the Step 3 section.');
345
+ process.exit(1);
346
+ }
347
+
348
+ // Replace Breaking Changes section
349
+ let updatedContent = migrationContent;
350
+
351
+ const breakingStartIndex = updatedContent.indexOf(breakingStartMarker) + breakingStartMarker.length;
352
+ const breakingEndIndex = updatedContent.indexOf(breakingEndMarker);
353
+
354
+ updatedContent =
355
+ updatedContent.substring(0, breakingStartIndex) +
356
+ '\n\n' + newBreakingChanges +
357
+ updatedContent.substring(breakingEndIndex);
358
+
359
+ // Replace Token Renames section
360
+ const renamesStartIndex = updatedContent.indexOf(renamesStartMarker) + renamesStartMarker.length;
361
+ const renamesEndIndex = updatedContent.indexOf(renamesEndMarker);
362
+
363
+ updatedContent =
364
+ updatedContent.substring(0, renamesStartIndex) +
365
+ '\n\n' + newTokenRenames +
366
+ updatedContent.substring(renamesEndIndex);
367
+
368
+ // Write updated content
369
+ try {
370
+ writeFileSync(migrationGuidePath, updatedContent, 'utf8');
371
+ console.log('āœ… Updated MIGRATION-v2.md');
372
+ console.log('\nšŸ“Š Generated:');
373
+ console.log(` File renames: ${mappings.files.renames?.length || 0}`);
374
+ console.log(` Token renames: ${mappings.tokens.renames?.length || 0}`);
375
+ console.log(` Token patterns: ${mappings.tokens.patterns?.length || 0}`);
376
+ console.log(` Token removals: ${mappings.tokens.removals?.length || 0}`);
377
+ console.log(` Value changes: ${mappings.tokens.valueChanges?.length || 0}`);
378
+ console.log('\nāœ… Auto-generated sections from mappings.json:');
379
+ console.log(' - Breaking Changes summary');
380
+ console.log(' - Step 3: Token Renames (detailed)');
381
+ } catch (error) {
382
+ console.error('āŒ Failed to write MIGRATION-v2.md:', error.message);
383
+ process.exit(1);
384
+ }