@@ -196,6 +196,244 @@ The metadata package is designed as a Layer 3 package in the ObjectStack archite
196196 └── @objectstack/objectql (registry persistence)
197197```
198198
199+ ## Common Workflows
200+
201+ ### Development Workflow with File Watching
202+
203+ ``` typescript
204+ import { MetadataManager } from ' @objectstack/metadata' ;
205+
206+ const manager = new MetadataManager ({
207+ rootDir: ' ./metadata' ,
208+ watch: true , // Enable file watching
209+ cache: { enabled: true , ttl: 3600 }
210+ });
211+
212+ // Watch for changes and reload
213+ manager .watch (' object' , async (event ) => {
214+ if (event .type === ' modified' || event .type === ' added' ) {
215+ console .log (` Reloading object: ${event .name } ` );
216+ const updated = await manager .load (' object' , event .name );
217+
218+ // Notify the system to reload
219+ await objectQL .reloadObject (event .name , updated );
220+ }
221+ });
222+
223+ // Hot module replacement for development
224+ console .log (' Watching metadata files for changes...' );
225+ ```
226+
227+ ### Metadata Migration Workflow
228+
229+ ``` typescript
230+ import { MetadataManager } from ' @objectstack/metadata' ;
231+
232+ async function migrateMetadata() {
233+ const manager = new MetadataManager ({
234+ rootDir: ' ./metadata'
235+ });
236+
237+ // 1. Load all existing objects
238+ const objects = await manager .loadMany (' object' );
239+
240+ // 2. Transform metadata (e.g., rename field)
241+ const transformed = objects .map (obj => ({
242+ ... obj ,
243+ fields: Object .entries (obj .fields ).reduce ((acc , [key , field ]) => {
244+ // Rename 'description' to 'notes'
245+ const newKey = key === ' description' ? ' notes' : key ;
246+ acc [newKey ] = field ;
247+ return acc ;
248+ }, {})
249+ }));
250+
251+ // 3. Save with backup
252+ for (const obj of transformed ) {
253+ await manager .save (' object' , obj .name , obj , {
254+ format: ' typescript' ,
255+ backup: true , // Create .bak file
256+ prettify: true
257+ });
258+ }
259+
260+ console .log (` Migrated ${objects .length } objects ` );
261+ }
262+ ```
263+
264+ ### Multi-Format Support Workflow
265+
266+ ``` typescript
267+ import { MetadataManager } from ' @objectstack/metadata' ;
268+
269+ const manager = new MetadataManager ({
270+ rootDir: ' ./metadata' ,
271+ formats: [' typescript' , ' json' , ' yaml' ]
272+ });
273+
274+ // Load from any format - manager auto-detects
275+ const customer = await manager .load (' object' , ' customer' );
276+ // Tries: customer.object.ts, customer.object.json, customer.object.yaml
277+
278+ // Save in preferred format
279+ await manager .save (' object' , ' customer' , customer , {
280+ format: ' typescript' // Convert to TypeScript
281+ });
282+
283+ // Generate documentation from metadata
284+ const allObjects = await manager .loadMany (' object' );
285+ const docs = allObjects .map (obj => `
286+ ## ${obj .label }
287+
288+ **Name:** ${obj .name }
289+
290+ **Fields:**
291+ ${Object .entries (obj .fields ).map (([name , field ]) =>
292+ ` - **${field .label }** (\` ${name }\` ): ${field .type } `
293+ ).join (' \n ' )}
294+ ` ).join (' \n\n ' );
295+
296+ fs .writeFileSync (' docs/objects.md' , docs );
297+ ```
298+
299+ ### Validation and Testing Workflow
300+
301+ ``` typescript
302+ import { MetadataManager } from ' @objectstack/metadata' ;
303+ import { ObjectSchema } from ' @objectstack/spec/data' ;
304+
305+ async function validateAllMetadata() {
306+ const manager = new MetadataManager ({
307+ rootDir: ' ./metadata'
308+ });
309+
310+ const objects = await manager .loadMany (' object' );
311+ const errors = [];
312+
313+ for (const obj of objects ) {
314+ const result = ObjectSchema .safeParse (obj );
315+
316+ if (! result .success ) {
317+ errors .push ({
318+ name: obj .name ,
319+ issues: result .error .issues
320+ });
321+ }
322+ }
323+
324+ if (errors .length > 0 ) {
325+ console .error (' Validation errors found:' );
326+ errors .forEach (({ name , issues }) => {
327+ console .error (` \n ${name }:` );
328+ issues .forEach (issue => {
329+ console .error (` - ${issue .path .join (' .' )}: ${issue .message } ` );
330+ });
331+ });
332+ process .exit (1 );
333+ }
334+
335+ console .log (` ✅ All ${objects .length } objects validated successfully ` );
336+ }
337+ ```
338+
339+ ### Metadata Versioning Workflow
340+
341+ ``` typescript
342+ import { MetadataManager } from ' @objectstack/metadata' ;
343+ import { execSync } from ' child_process' ;
344+
345+ async function versionMetadata() {
346+ const manager = new MetadataManager ({
347+ rootDir: ' ./metadata'
348+ });
349+
350+ const objects = await manager .loadMany (' object' );
351+
352+ // Add version metadata
353+ const versioned = objects .map (obj => ({
354+ ... obj ,
355+ metadata: {
356+ ... obj .metadata ,
357+ version: ' 2.0.0' ,
358+ lastModified: new Date ().toISOString (),
359+ modifiedBy: execSync (' git config user.name' ).toString ().trim ()
360+ }
361+ }));
362+
363+ // Save versioned metadata
364+ for (const obj of versioned ) {
365+ await manager .save (' object' , obj .name , obj , {
366+ format: ' typescript' ,
367+ prettify: true
368+ });
369+ }
370+
371+ // Commit to version control
372+ execSync (' git add metadata/' );
373+ execSync (' git commit -m "Version bump to 2.0.0"' );
374+ }
375+ ```
376+
377+ ### Import/Export Workflow
378+
379+ ``` typescript
380+ import { MetadataManager } from ' @objectstack/metadata' ;
381+
382+ async function exportToJSON() {
383+ const manager = new MetadataManager ({
384+ rootDir: ' ./metadata'
385+ });
386+
387+ // Load all metadata
388+ const [objects, views, apps] = await Promise .all ([
389+ manager .loadMany (' object' ),
390+ manager .loadMany (' view' ),
391+ manager .loadMany (' app' )
392+ ]);
393+
394+ // Create unified export
395+ const exportData = {
396+ version: ' 1.0.0' ,
397+ exported: new Date ().toISOString (),
398+ objects ,
399+ views ,
400+ apps
401+ };
402+
403+ // Save as single JSON file
404+ fs .writeFileSync (
405+ ' export/metadata-export.json' ,
406+ JSON .stringify (exportData , null , 2 )
407+ );
408+
409+ console .log (' Export complete!' );
410+ }
411+
412+ async function importFromJSON(filePath : string ) {
413+ const manager = new MetadataManager ({
414+ rootDir: ' ./metadata'
415+ });
416+
417+ const importData = JSON .parse (fs .readFileSync (filePath , ' utf-8' ));
418+
419+ // Import objects
420+ for (const obj of importData .objects ) {
421+ await manager .save (' object' , obj .name , obj , {
422+ format: ' typescript'
423+ });
424+ }
425+
426+ // Import views
427+ for (const view of importData .views ) {
428+ await manager .save (' view' , view .name , view , {
429+ format: ' typescript'
430+ });
431+ }
432+
433+ console .log (' Import complete!' );
434+ }
435+ ```
436+
199437## License
200438
201439MIT
0 commit comments