@objectstack/metadata 1.0.0 → 1.0.1

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,124 @@
1
+ /**
2
+ * Node Metadata Manager
3
+ *
4
+ * Extends MetadataManager with Filesystem capabilities (Watching, default loader)
5
+ */
6
+
7
+ import * as path from 'node:path';
8
+ import { watch as chokidarWatch, type FSWatcher } from 'chokidar';
9
+ import type {
10
+ MetadataWatchEvent,
11
+ } from '@objectstack/spec/system';
12
+ import { FilesystemLoader } from './loaders/filesystem-loader.js';
13
+ import { MetadataManager, type MetadataManagerOptions } from './metadata-manager.js';
14
+
15
+ /**
16
+ * Node metadata manager class
17
+ */
18
+ export class NodeMetadataManager extends MetadataManager {
19
+ private watcher?: FSWatcher;
20
+
21
+ constructor(config: MetadataManagerOptions) {
22
+ super(config);
23
+
24
+ // Initialize Default Filesystem Loader if no loaders provided
25
+ // This logic replaces the removed logic from base class
26
+ if (!config.loaders || config.loaders.length === 0) {
27
+ const rootDir = config.rootDir || process.cwd();
28
+ this.registerLoader(new FilesystemLoader(rootDir, this.serializers, this.logger));
29
+ }
30
+
31
+ // Start watching if enabled
32
+ if (config.watch) {
33
+ this.startWatching();
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Stop all watching
39
+ */
40
+ async stopWatching(): Promise<void> {
41
+ if (this.watcher) {
42
+ await this.watcher.close();
43
+ this.watcher = undefined;
44
+ }
45
+ // Call base cleanup if any
46
+ }
47
+
48
+ /**
49
+ * Start watching for file changes
50
+ */
51
+ private startWatching(): void {
52
+ const rootDir = this.config.rootDir || process.cwd();
53
+ const { ignored = ['**/node_modules/**', '**/*.test.*'], persistent = true } =
54
+ this.config.watchOptions || {};
55
+
56
+ this.watcher = chokidarWatch(rootDir, {
57
+ ignored,
58
+ persistent,
59
+ ignoreInitial: true,
60
+ });
61
+
62
+ this.watcher.on('add', async (filePath) => {
63
+ await this.handleFileEvent('added', filePath);
64
+ });
65
+
66
+ this.watcher.on('change', async (filePath) => {
67
+ await this.handleFileEvent('changed', filePath);
68
+ });
69
+
70
+ this.watcher.on('unlink', async (filePath) => {
71
+ await this.handleFileEvent('deleted', filePath);
72
+ });
73
+
74
+ this.logger.info('File watcher started', { rootDir });
75
+ }
76
+
77
+ /**
78
+ * Handle file change events
79
+ */
80
+ private async handleFileEvent(
81
+ eventType: 'added' | 'changed' | 'deleted',
82
+ filePath: string
83
+ ): Promise<void> {
84
+ const rootDir = this.config.rootDir || process.cwd();
85
+ const relativePath = path.relative(rootDir, filePath);
86
+ const parts = relativePath.split(path.sep);
87
+
88
+ if (parts.length < 2) {
89
+ return; // Not a metadata file
90
+ }
91
+
92
+ const type = parts[0];
93
+ const fileName = parts[parts.length - 1];
94
+ const name = path.basename(fileName, path.extname(fileName));
95
+
96
+ // We can't access private watchCallbacks from parent.
97
+ // We need a protected method to trigger watch event or access it.
98
+ // OPTION: Add a method `triggerWatchEvent` to MetadataManager
99
+
100
+ let data: any = undefined;
101
+ if (eventType !== 'deleted') {
102
+ try {
103
+ data = await this.load(type, name, { useCache: false });
104
+ } catch (error) {
105
+ this.logger.error('Failed to load changed file', undefined, {
106
+ filePath,
107
+ error: error instanceof Error ? error.message : String(error),
108
+ });
109
+ return;
110
+ }
111
+ }
112
+
113
+ const event: MetadataWatchEvent = {
114
+ type: eventType,
115
+ metadataType: type,
116
+ name,
117
+ path: filePath,
118
+ data,
119
+ timestamp: new Date(),
120
+ };
121
+
122
+ this.notifyWatchers(type, event);
123
+ }
124
+ }
package/src/node.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Node.js specific exports for @objectstack/metadata
3
+ */
4
+
5
+ export * from './index.js';
6
+ export { NodeMetadataManager } from './node-metadata-manager.js';
7
+ export { FilesystemLoader } from './loaders/filesystem-loader.js';
8
+ export { MetadataPlugin } from './plugin.js';
package/src/plugin.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Plugin, PluginContext } from '@objectstack/core';
2
- import { MetadataManager } from './metadata-manager.js';
2
+ import { NodeMetadataManager } from './node-metadata-manager.js';
3
3
  import { ObjectStackDefinitionSchema } from '@objectstack/spec';
4
4
 
5
5
  export interface MetadataPluginOptions {
@@ -11,7 +11,7 @@ export class MetadataPlugin implements Plugin {
11
11
  name = 'com.objectstack.metadata';
12
12
  version = '1.0.0';
13
13
 
14
- private manager: MetadataManager;
14
+ private manager: NodeMetadataManager;
15
15
  private options: MetadataPluginOptions;
16
16
 
17
17
  constructor(options: MetadataPluginOptions = {}) {
@@ -22,7 +22,7 @@ export class MetadataPlugin implements Plugin {
22
22
 
23
23
  const rootDir = this.options.rootDir || process.cwd();
24
24
 
25
- this.manager = new MetadataManager({
25
+ this.manager = new NodeMetadataManager({
26
26
  rootDir,
27
27
  watch: this.options.watch ?? true,
28
28
  formats: ['yaml', 'json', 'typescript', 'javascript']