create-wp-typia 0.1.0
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 +33 -0
- package/dist/cli.js +87837 -0
- package/dist/highlights-eq9cgrbb.scm +604 -0
- package/dist/highlights-ghv9g403.scm +205 -0
- package/dist/highlights-hk7bwhj4.scm +284 -0
- package/dist/highlights-r812a2qc.scm +150 -0
- package/dist/highlights-x6tmsnaa.scm +115 -0
- package/dist/injections-73j83es3.scm +27 -0
- package/dist/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
- package/dist/tree-sitter-markdown-411r6y9b.wasm +0 -0
- package/dist/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
- package/dist/tree-sitter-typescript-zxjzwt75.wasm +0 -0
- package/dist/tree-sitter-zig-e78zbjpm.wasm +0 -0
- package/lib/entry.js +29 -0
- package/lib/node-cli.js +326 -0
- package/lib/package-managers.d.ts +29 -0
- package/lib/package-managers.js +170 -0
- package/lib/scaffold.d.ts +64 -0
- package/lib/scaffold.js +565 -0
- package/lib/template-registry.d.ts +18 -0
- package/lib/template-registry.js +58 -0
- package/package.json +64 -0
- package/src/cli.ts +329 -0
- package/templates/advanced/README.md.mustache +70 -0
- package/templates/advanced/block.json.mustache +42 -0
- package/templates/advanced/index.js +21 -0
- package/templates/advanced/package.json.mustache +48 -0
- package/templates/advanced/scripts/generate-migrations.ts.mustache +267 -0
- package/templates/advanced/scripts/lib/typia-metadata-core.ts +806 -0
- package/templates/advanced/scripts/migration-cli.ts.mustache +260 -0
- package/templates/advanced/scripts/sync-types-to-block-json.ts.mustache +25 -0
- package/templates/advanced/src/admin/migration-dashboard.tsx.mustache +450 -0
- package/templates/advanced/src/components/ErrorBoundary.tsx.mustache +47 -0
- package/templates/advanced/src/deprecated.ts.mustache +184 -0
- package/templates/advanced/src/edit.tsx.mustache +93 -0
- package/templates/advanced/src/hooks/useDebounce.ts.mustache +20 -0
- package/templates/advanced/src/hooks/useLocalStorage.ts.mustache +31 -0
- package/templates/advanced/src/hooks.ts.mustache +56 -0
- package/templates/advanced/src/index.tsx.mustache +16 -0
- package/templates/advanced/src/migration-detector.ts.mustache +417 -0
- package/templates/advanced/src/migrations/index.ts.mustache +361 -0
- package/templates/advanced/src/save.tsx.mustache +40 -0
- package/templates/advanced/src/style.scss.mustache +84 -0
- package/templates/advanced/src/types/versions.ts.mustache +108 -0
- package/templates/advanced/src/types.ts.mustache +45 -0
- package/templates/advanced/src/utils/classnames.ts.mustache +51 -0
- package/templates/advanced/src/utils/debounce.ts.mustache +37 -0
- package/templates/advanced/src/utils/index.ts.mustache +7 -0
- package/templates/advanced/src/utils/uuid.ts.mustache +17 -0
- package/templates/advanced/src/validators.ts.mustache +39 -0
- package/templates/advanced/src/view.ts.mustache +59 -0
- package/templates/advanced/tsconfig.json.mustache +9 -0
- package/templates/advanced/webpack.config.js.mustache +85 -0
- package/templates/basic/package.json.mustache +39 -0
- package/templates/basic/scripts/lib/typia-metadata-core.ts +806 -0
- package/templates/basic/scripts/sync-types-to-block-json.ts +25 -0
- package/templates/basic/src/block.json +51 -0
- package/templates/basic/src/edit.tsx +85 -0
- package/templates/basic/src/hooks.ts +75 -0
- package/templates/basic/src/index.tsx +37 -0
- package/templates/basic/src/save.tsx +27 -0
- package/templates/basic/src/style.scss +42 -0
- package/templates/basic/src/types.ts +47 -0
- package/templates/basic/src/validators.ts +39 -0
- package/templates/basic/tsconfig.json +20 -0
- package/templates/basic/webpack.config.js +85 -0
- package/templates/full/package.json.mustache +40 -0
- package/templates/full/scripts/lib/typia-metadata-core.ts +806 -0
- package/templates/full/scripts/sync-types-to-block-json.ts.mustache +25 -0
- package/templates/full/src/block.json.mustache +121 -0
- package/templates/full/src/edit.tsx.mustache +300 -0
- package/templates/full/src/editor.scss.mustache +251 -0
- package/templates/full/src/hooks.ts.mustache +140 -0
- package/templates/full/src/index.tsx.mustache +27 -0
- package/templates/full/src/save.tsx.mustache +39 -0
- package/templates/full/src/style.scss.mustache +224 -0
- package/templates/full/src/types.ts.mustache +34 -0
- package/templates/full/src/validators.ts.mustache +84 -0
- package/templates/full/tsconfig.json.mustache +9 -0
- package/templates/full/webpack.config.js.mustache +85 -0
- package/templates/interactivity/package.json.mustache +41 -0
- package/templates/interactivity/scripts/lib/typia-metadata-core.ts +806 -0
- package/templates/interactivity/scripts/sync-types-to-block-json.ts.mustache +25 -0
- package/templates/interactivity/src/block.json.mustache +75 -0
- package/templates/interactivity/src/edit.tsx.mustache +206 -0
- package/templates/interactivity/src/interactivity.ts.mustache +183 -0
- package/templates/interactivity/src/save.tsx.mustache +87 -0
- package/templates/interactivity/src/types.ts.mustache +29 -0
- package/templates/interactivity/tsconfig.json.mustache +9 -0
- package/templates/interactivity/webpack.config.js.mustache +85 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import typia from "typia";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 🚀 Auto-generate WordPress block migrations from Typia types
|
|
7
|
+
*
|
|
8
|
+
* This script analyzes type differences and generates migration functions
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
interface TypeField {
|
|
12
|
+
name: string;
|
|
13
|
+
type: string;
|
|
14
|
+
optional: boolean;
|
|
15
|
+
defaultValue?: any;
|
|
16
|
+
tags: string[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface VersionInfo {
|
|
20
|
+
version: string;
|
|
21
|
+
fields: TypeField[];
|
|
22
|
+
breaking: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function generateMigrations() {
|
|
26
|
+
try {
|
|
27
|
+
console.log('🔄 Analyzing type versions for {{title}}...');
|
|
28
|
+
|
|
29
|
+
// Read types file
|
|
30
|
+
const typesContent = fs.readFileSync('src/types/versions.ts', 'utf-8');
|
|
31
|
+
const versions = extractVersionInfo(typesContent);
|
|
32
|
+
|
|
33
|
+
console.log(`📋 Found ${versions.length} versions:`, versions.map(v => v.version));
|
|
34
|
+
|
|
35
|
+
// Generate migration functions
|
|
36
|
+
const migrations = generateMigrationFunctions(versions);
|
|
37
|
+
|
|
38
|
+
// Update migrations file
|
|
39
|
+
const migrationsContent = generateMigrationsFile(migrations);
|
|
40
|
+
fs.writeFileSync('src/migrations/auto-generated.ts', migrationsContent);
|
|
41
|
+
|
|
42
|
+
// Update block.json with deprecated versions
|
|
43
|
+
updateBlockJsonDeprecated(versions);
|
|
44
|
+
|
|
45
|
+
console.log('✅ Migration generation complete!');
|
|
46
|
+
console.log('📝 Generated files:');
|
|
47
|
+
console.log(' - src/migrations/auto-generated.ts');
|
|
48
|
+
console.log(' - Updated block.json with deprecated versions');
|
|
49
|
+
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error('❌ Migration generation failed:', error);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function extractVersionInfo(content: string): VersionInfo[] {
|
|
57
|
+
const versions: VersionInfo[] = [];
|
|
58
|
+
|
|
59
|
+
// Parse interface definitions
|
|
60
|
+
const interfaceRegex = /interface\s+({{titleCase}}AttributesV\d+)\s*\{([^}]+)\}/g;
|
|
61
|
+
let match;
|
|
62
|
+
|
|
63
|
+
while ((match = interfaceRegex.exec(content)) !== null) {
|
|
64
|
+
const [, interfaceName, body] = match;
|
|
65
|
+
const versionNumber = interfaceName.match(/V(\d+)/)?.[1] || '1';
|
|
66
|
+
|
|
67
|
+
const fields = parseFields(body);
|
|
68
|
+
const isBreaking = content.includes(`breaking: true`) && content.includes(`version: ${versionNumber}`);
|
|
69
|
+
|
|
70
|
+
versions.push({
|
|
71
|
+
version: `${versionNumber}.0.0`,
|
|
72
|
+
fields,
|
|
73
|
+
breaking: isBreaking
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return versions.sort((a, b) => parseInt(a.version) - parseInt(b.version));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function parseFields(interfaceBody: string): TypeField[] {
|
|
81
|
+
const fields: TypeField[] = [];
|
|
82
|
+
const fieldRegex = /(.*?):\s*([^;]+);/g;
|
|
83
|
+
let match;
|
|
84
|
+
|
|
85
|
+
while ((match = fieldRegex.exec(interfaceBody)) !== null) {
|
|
86
|
+
const [, fieldDecl, typeDecl] = match;
|
|
87
|
+
const fieldName = fieldDecl.trim().replace(/\?$/, '');
|
|
88
|
+
const optional = fieldDecl.includes('?');
|
|
89
|
+
|
|
90
|
+
// Extract tags
|
|
91
|
+
const tags = extractTags(typeDecl);
|
|
92
|
+
const defaultValue = extractDefault(typeDecl);
|
|
93
|
+
const baseType = extractBaseType(typeDecl);
|
|
94
|
+
|
|
95
|
+
fields.push({
|
|
96
|
+
name: fieldName,
|
|
97
|
+
type: baseType,
|
|
98
|
+
optional,
|
|
99
|
+
defaultValue,
|
|
100
|
+
tags
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return fields;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function extractTags(typeDecl: string): string[] {
|
|
108
|
+
const tagMatches = typeDecl.match(/tags\.\w+(?:<[^>]+>)?/g) || [];
|
|
109
|
+
return tagMatches;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function extractDefault(typeDecl: string): any {
|
|
113
|
+
const defaultMatch = typeDecl.match(/tags\.Default<([^>]+)>/);
|
|
114
|
+
if (!defaultMatch) return undefined;
|
|
115
|
+
|
|
116
|
+
const value = defaultMatch[1].trim();
|
|
117
|
+
if (value === 'true') return true;
|
|
118
|
+
if (value === 'false') return false;
|
|
119
|
+
if (value.match(/^\d+$/)) return parseInt(value);
|
|
120
|
+
if (value.startsWith('"') && value.endsWith('"')) return value.slice(1, -1);
|
|
121
|
+
return value;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function extractBaseType(typeDecl: string): string {
|
|
125
|
+
// Remove tags and get base type
|
|
126
|
+
const cleanType = typeDecl.replace(/\s*&\s*tags\.[^&]+/g, '').trim();
|
|
127
|
+
if (cleanType.startsWith('string')) return 'string';
|
|
128
|
+
if (cleanType.startsWith('number')) return 'number';
|
|
129
|
+
if (cleanType.startsWith('boolean')) return 'boolean';
|
|
130
|
+
if (cleanType.includes('|')) return 'union';
|
|
131
|
+
return 'unknown';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function generateMigrationFunctions(versions: VersionInfo[]): string[] {
|
|
135
|
+
const migrations: string[] = [];
|
|
136
|
+
|
|
137
|
+
for (let i = 0; i < versions.length - 1; i++) {
|
|
138
|
+
const fromVersion = versions[i];
|
|
139
|
+
const toVersion = versions[i + 1];
|
|
140
|
+
|
|
141
|
+
const migrationCode = generateSingleMigration(fromVersion, toVersion);
|
|
142
|
+
migrations.push(migrationCode);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return migrations;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function generateSingleMigration(from: VersionInfo, to: VersionInfo): string {
|
|
149
|
+
const fromV = from.version.split('.')[0];
|
|
150
|
+
const toV = to.version.split('.')[0];
|
|
151
|
+
|
|
152
|
+
let migrationBody = '';
|
|
153
|
+
|
|
154
|
+
// Handle each field
|
|
155
|
+
for (const toField of to.fields) {
|
|
156
|
+
const fromField = from.fields.find(f => f.name === toField.name);
|
|
157
|
+
|
|
158
|
+
if (!fromField) {
|
|
159
|
+
// New field - use default
|
|
160
|
+
if (toField.defaultValue !== undefined) {
|
|
161
|
+
migrationBody += `\t\t${toField.name}: ${JSON.stringify(toField.defaultValue)},\n`;
|
|
162
|
+
} else if (toField.optional) {
|
|
163
|
+
migrationBody += `\t\t${toField.name}: undefined,\n`;
|
|
164
|
+
} else {
|
|
165
|
+
migrationBody += `\t\t// TODO: Handle required field '${toField.name}' that doesn't exist in v${fromV}\n`;
|
|
166
|
+
migrationBody += `\t\t${toField.name}: ${getTypeDefault(toField.type)},\n`;
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
// Existing field - copy or transform
|
|
170
|
+
if (fromField.type === toField.type) {
|
|
171
|
+
migrationBody += `\t\t${toField.name}: v${fromV}Attrs.${toField.name}`;
|
|
172
|
+
if (toField.defaultValue !== undefined) {
|
|
173
|
+
migrationBody += ` ?? ${JSON.stringify(toField.defaultValue)}`;
|
|
174
|
+
}
|
|
175
|
+
migrationBody += ',\n';
|
|
176
|
+
} else {
|
|
177
|
+
migrationBody += `\t\t// TODO: Transform ${toField.name} from ${fromField.type} to ${toField.type}\n`;
|
|
178
|
+
migrationBody += `\t\t${toField.name}: v${fromV}Attrs.${toField.name} as any,\n`;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return `
|
|
184
|
+
// V${fromV} → V${toV} Migration (Auto-generated)
|
|
185
|
+
export function migrateV${fromV}ToV${toV}(v${fromV}Attrs: {{titleCase}}AttributesV${fromV}): {{titleCase}}AttributesV${toV} {
|
|
186
|
+
console.log('🔄 Auto-migrating {{title}} from v${fromV} to v${toV}');
|
|
187
|
+
|
|
188
|
+
const migrated: {{titleCase}}AttributesV${toV} = {
|
|
189
|
+
${migrationBody.trimEnd()}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// Validate migrated data
|
|
193
|
+
const validation = typia.validate<{{titleCase}}AttributesV${toV}>(migrated);
|
|
194
|
+
if (!validation.success) {
|
|
195
|
+
console.error('❌ V${fromV}→V${toV} migration validation failed:', validation.errors);
|
|
196
|
+
throw new Error('Auto-migration validation failed');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
console.log('✅ V${fromV}→V${toV} auto-migration successful');
|
|
200
|
+
return migrated;
|
|
201
|
+
}`;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function getTypeDefault(type: string): string {
|
|
205
|
+
switch (type) {
|
|
206
|
+
case 'string': return '""';
|
|
207
|
+
case 'number': return '0';
|
|
208
|
+
case 'boolean': return 'false';
|
|
209
|
+
case 'union': return '""'; // Assume string union
|
|
210
|
+
default: return 'undefined';
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function generateMigrationsFile(migrations: string[]): string {
|
|
215
|
+
return `/**
|
|
216
|
+
* 🤖 AUTO-GENERATED MIGRATIONS
|
|
217
|
+
* Generated by generate-migrations script from Typia types
|
|
218
|
+
* Do not edit manually - regenerate with: bun run generate-migrations
|
|
219
|
+
*/
|
|
220
|
+
|
|
221
|
+
import typia from "typia";
|
|
222
|
+
import {
|
|
223
|
+
{{titleCase}}AttributesV1,
|
|
224
|
+
{{titleCase}}AttributesV2,
|
|
225
|
+
{{titleCase}}AttributesV3,
|
|
226
|
+
{{titleCase}}Attributes
|
|
227
|
+
} from '../types/versions';
|
|
228
|
+
|
|
229
|
+
${migrations.join('\n')}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Auto-migration registry
|
|
233
|
+
*/
|
|
234
|
+
export const AUTO_MIGRATIONS = {
|
|
235
|
+
${migrations.map(m => {
|
|
236
|
+
const match = m.match(/migrateV(\d+)ToV(\d+)/);
|
|
237
|
+
if (match) {
|
|
238
|
+
return `\t"${match[1]}.0.0->${match[2]}.0.0": migrateV${match[1]}ToV${match[2]},`;
|
|
239
|
+
}
|
|
240
|
+
return '';
|
|
241
|
+
}).filter(Boolean).join('\n')}
|
|
242
|
+
} as const;
|
|
243
|
+
`;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function updateBlockJsonDeprecated(versions: VersionInfo[]) {
|
|
247
|
+
const blockJsonPath = 'src/{{slug}}/block.json';
|
|
248
|
+
if (!fs.existsSync(blockJsonPath)) return;
|
|
249
|
+
|
|
250
|
+
const blockJson = JSON.parse(fs.readFileSync(blockJsonPath, 'utf-8'));
|
|
251
|
+
|
|
252
|
+
// Add deprecated versions
|
|
253
|
+
const deprecated = versions.slice(0, -1).map((version, index) => ({
|
|
254
|
+
version: version.version,
|
|
255
|
+
isEligible: true,
|
|
256
|
+
migrate: `migrateV${parseInt(version.version)}ToV${parseInt(versions[index + 1].version)}`
|
|
257
|
+
}));
|
|
258
|
+
|
|
259
|
+
if (deprecated.length > 0) {
|
|
260
|
+
blockJson.deprecated = deprecated;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
fs.writeFileSync(blockJsonPath, JSON.stringify(blockJson, null, '\t'));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Run script
|
|
267
|
+
generateMigrations().catch(console.error);
|