Skip to content

Commit e9984a3

Browse files
Copilothotlong
andcommitted
Add comprehensive workflow examples and plugin patterns to package READMEs
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 0c7e6e1 commit e9984a3

3 files changed

Lines changed: 800 additions & 0 deletions

File tree

packages/metadata/README.md

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

201439
MIT

0 commit comments

Comments
 (0)