@memberjunction/metadata-sync 2.53.0 → 2.54.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 CHANGED
@@ -756,6 +756,84 @@ Support environment-specific values:
756
756
  - `@env:VARIABLE_NAME`
757
757
  - Useful for different environments (dev/staging/prod)
758
758
 
759
+ ### {@include} References in Files (NEW)
760
+ Enable content composition within non-JSON files (like .md, .html, .txt) using JSDoc-style include syntax:
761
+ - Pattern: `{@include path/to/file.ext}`
762
+ - Supports relative paths from the containing file
763
+ - Recursive includes (includes within includes)
764
+ - Circular reference detection prevents infinite loops
765
+ - Works seamlessly with `@file:` references
766
+
767
+ #### How It Works
768
+ When a JSON metadata file uses `@file:` to reference an external file, the MetadataSync tool:
769
+ 1. Loads the referenced file
770
+ 2. Scans for `{@include}` patterns
771
+ 3. Recursively resolves all includes
772
+ 4. Returns the fully composed content
773
+
774
+ #### Example Usage
775
+ ```markdown
776
+ # My Prompt Template
777
+
778
+ ## System Instructions
779
+ {@include ./shared/system-instructions.md}
780
+
781
+ ## Context
782
+ {@include ../common/context-header.md}
783
+
784
+ ## Task
785
+ Please analyze the following...
786
+ ```
787
+
788
+ #### Complex Example with Nested Includes
789
+ Directory structure:
790
+ ```
791
+ prompts/
792
+ ├── customer-service/
793
+ │ ├── greeting.json # Uses @file:greeting.md
794
+ │ ├── greeting.md # Contains {@include} references
795
+ │ └── shared/
796
+ │ ├── tone.md
797
+ │ └── guidelines.md
798
+ └── common/
799
+ ├── company-info.md
800
+ └── legal-disclaimer.md
801
+ ```
802
+
803
+ greeting.json:
804
+ ```json
805
+ {
806
+ "fields": {
807
+ "Name": "Customer Greeting",
808
+ "Prompt": "@file:greeting.md"
809
+ }
810
+ }
811
+ ```
812
+
813
+ greeting.md:
814
+ ```markdown
815
+ # Customer Service Greeting
816
+
817
+ {@include ./shared/tone.md}
818
+
819
+ ## Guidelines
820
+ {@include ./shared/guidelines.md}
821
+
822
+ ## Company Information
823
+ {@include ../common/company-info.md}
824
+
825
+ ## Legal
826
+ {@include ../common/legal-disclaimer.md}
827
+ ```
828
+
829
+ The final content pushed to the database will have all includes fully resolved.
830
+
831
+ Benefits:
832
+ - **DRY Principle**: Share common content across multiple files
833
+ - **Maintainability**: Update shared content in one place
834
+ - **Flexibility**: Build complex documents from modular parts
835
+ - **Validation**: Automatic checking of included file existence and circular references
836
+
759
837
  ### @template: References (NEW)
760
838
  Enable JSON template composition for reusable configurations:
761
839
 
@@ -52,7 +52,7 @@ export declare class SyncEngine {
52
52
  * Initializes the sync engine by refreshing metadata cache
53
53
  * @returns Promise that resolves when initialization is complete
54
54
  */
55
- initialize(): Promise<void>;
55
+ initialize(forceRefresh?: boolean): Promise<void>;
56
56
  /**
57
57
  * Process special references in field values
58
58
  *
@@ -254,6 +254,33 @@ export declare class SyncEngine {
254
254
  * @private
255
255
  */
256
256
  private loadAndProcessTemplate;
257
+ /**
258
+ * Process file content with {@include} references
259
+ *
260
+ * Recursively processes a file's content to resolve `{@include path}` references.
261
+ * Include references use JSDoc-style syntax and support:
262
+ * - Relative paths resolved from the containing file's directory
263
+ * - Recursive includes (includes within included files)
264
+ * - Circular reference detection to prevent infinite loops
265
+ * - Seamless content substitution maintaining surrounding text
266
+ *
267
+ * @param filePath - Path to the file being processed
268
+ * @param content - The file content to process
269
+ * @param visitedPaths - Set of already visited file paths for circular reference detection
270
+ * @returns Promise resolving to the content with all includes resolved
271
+ * @throws Error if circular reference detected or included file not found
272
+ *
273
+ * @example
274
+ * ```typescript
275
+ * // Content with include reference
276
+ * const content = 'This is a {@include ./shared/header.md} example';
277
+ *
278
+ * // Resolves to:
279
+ * const result = await processFileContentWithIncludes('/path/to/file.md', content);
280
+ * // 'This is a [contents of header.md] example'
281
+ * ```
282
+ */
283
+ private processFileContentWithIncludes;
257
284
  /**
258
285
  * Deep merge two objects with target taking precedence
259
286
  *
@@ -47,9 +47,10 @@ class SyncEngine {
47
47
  * Initializes the sync engine by refreshing metadata cache
48
48
  * @returns Promise that resolves when initialization is complete
49
49
  */
50
- async initialize() {
51
- // Initialize metadata
52
- await this.metadata.Refresh();
50
+ async initialize(forceRefresh = false) {
51
+ if (forceRefresh) {
52
+ await this.metadata.Refresh();
53
+ }
53
54
  }
54
55
  /**
55
56
  * Process special references in field values
@@ -103,7 +104,9 @@ class SyncEngine {
103
104
  const filePath = value.substring(6);
104
105
  const fullPath = path_1.default.resolve(baseDir, filePath);
105
106
  if (await fs_extra_1.default.pathExists(fullPath)) {
106
- return await fs_extra_1.default.readFile(fullPath, 'utf-8');
107
+ const fileContent = await fs_extra_1.default.readFile(fullPath, 'utf-8');
108
+ // Process the file content for {@include} references
109
+ return await this.processFileContentWithIncludes(fullPath, fileContent);
107
110
  }
108
111
  else {
109
112
  throw new Error(`File not found: ${fullPath}`);
@@ -573,6 +576,71 @@ class SyncEngine {
573
576
  throw new Error(`Failed to load template ${fullPath}: ${error}`);
574
577
  }
575
578
  }
579
+ /**
580
+ * Process file content with {@include} references
581
+ *
582
+ * Recursively processes a file's content to resolve `{@include path}` references.
583
+ * Include references use JSDoc-style syntax and support:
584
+ * - Relative paths resolved from the containing file's directory
585
+ * - Recursive includes (includes within included files)
586
+ * - Circular reference detection to prevent infinite loops
587
+ * - Seamless content substitution maintaining surrounding text
588
+ *
589
+ * @param filePath - Path to the file being processed
590
+ * @param content - The file content to process
591
+ * @param visitedPaths - Set of already visited file paths for circular reference detection
592
+ * @returns Promise resolving to the content with all includes resolved
593
+ * @throws Error if circular reference detected or included file not found
594
+ *
595
+ * @example
596
+ * ```typescript
597
+ * // Content with include reference
598
+ * const content = 'This is a {@include ./shared/header.md} example';
599
+ *
600
+ * // Resolves to:
601
+ * const result = await processFileContentWithIncludes('/path/to/file.md', content);
602
+ * // 'This is a [contents of header.md] example'
603
+ * ```
604
+ */
605
+ async processFileContentWithIncludes(filePath, content, visitedPaths = new Set()) {
606
+ // Add current file to visited set
607
+ const absolutePath = path_1.default.resolve(filePath);
608
+ if (visitedPaths.has(absolutePath)) {
609
+ throw new Error(`Circular reference detected: ${absolutePath} is already being processed`);
610
+ }
611
+ visitedPaths.add(absolutePath);
612
+ // Pattern to match {@include path} references
613
+ // Supports whitespace around the path for flexibility
614
+ const includePattern = /\{@include\s+([^\}]+)\s*\}/g;
615
+ let processedContent = content;
616
+ let match;
617
+ // Process all {@include} references
618
+ while ((match = includePattern.exec(content)) !== null) {
619
+ const [fullMatch, includePath] = match;
620
+ const trimmedPath = includePath.trim();
621
+ // Resolve the include path relative to the current file's directory
622
+ const currentDir = path_1.default.dirname(filePath);
623
+ const resolvedPath = path_1.default.resolve(currentDir, trimmedPath);
624
+ try {
625
+ // Check if the included file exists
626
+ if (!await fs_extra_1.default.pathExists(resolvedPath)) {
627
+ throw new Error(`Included file not found: ${resolvedPath}`);
628
+ }
629
+ // Read the included file
630
+ const includedContent = await fs_extra_1.default.readFile(resolvedPath, 'utf-8');
631
+ // Recursively process the included content for nested includes
632
+ const processedInclude = await this.processFileContentWithIncludes(resolvedPath, includedContent, new Set(visitedPaths) // Pass a copy to allow the same file in different branches
633
+ );
634
+ // Replace the {@include} reference with the processed content
635
+ processedContent = processedContent.replace(fullMatch, processedInclude);
636
+ }
637
+ catch (error) {
638
+ // Enhance error message with context
639
+ throw new Error(`Failed to process {@include ${trimmedPath}} in ${filePath}: ${error}`);
640
+ }
641
+ }
642
+ return processedContent;
643
+ }
576
644
  /**
577
645
  * Deep merge two objects with target taking precedence
578
646
  *
@@ -1 +1 @@
1
- {"version":3,"file":"sync-engine.js","sourceRoot":"","sources":["../../src/lib/sync-engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Core synchronization engine for MemberJunction metadata\n * @module sync-engine\n * \n * This module provides the core functionality for synchronizing metadata between\n * the MemberJunction database and local file system representations. It handles\n * special reference types (@file, @url, @lookup, @env, @parent, @root, @template),\n * manages entity operations, and provides utilities for data transformation.\n */\n\nimport path from 'path';\nimport fs from 'fs-extra';\nimport crypto from 'crypto';\nimport axios from 'axios';\nimport { EntityInfo, Metadata, RunView, BaseEntity, CompositeKey, UserInfo } from '@memberjunction/core';\nimport { uuidv4 } from '@memberjunction/global';\nimport { EntityConfig, FolderConfig } from '../config';\n\n/**\n * Represents the structure of a metadata record with optional sync tracking\n */\nexport interface RecordData {\n /** Primary key field(s) and their values */\n primaryKey?: Record<string, any>;\n /** Entity field names and their values */\n fields: Record<string, any>;\n /** Related entities organized by entity name */\n relatedEntities?: Record<string, RecordData[]>;\n /** Synchronization metadata for change tracking */\n sync?: {\n /** ISO timestamp of last modification */\n lastModified: string;\n /** SHA256 checksum of the fields object */\n checksum: string;\n };\n}\n\n/**\n * Core engine for synchronizing MemberJunction metadata between database and files\n * \n * @class SyncEngine\n * @example\n * ```typescript\n * const syncEngine = new SyncEngine(systemUser);\n * await syncEngine.initialize();\n * \n * // Process a field value with special references\n * const value = await syncEngine.processFieldValue('@lookup:Users.Email=admin@example.com', '/path/to/base');\n * ```\n */\nexport class SyncEngine {\n private metadata: Metadata;\n private contextUser: UserInfo;\n\n /**\n * Creates a new SyncEngine instance\n * @param contextUser - The user context for database operations\n */\n constructor(contextUser: UserInfo) {\n this.metadata = new Metadata();\n this.contextUser = contextUser;\n }\n \n /**\n * Initializes the sync engine by refreshing metadata cache\n * @returns Promise that resolves when initialization is complete\n */\n async initialize(): Promise<void> {\n // Initialize metadata\n await this.metadata.Refresh();\n }\n \n /**\n * Process special references in field values\n * \n * Handles the following reference types:\n * - `@parent:fieldName` - References a field from the parent record\n * - `@root:fieldName` - References a field from the root record\n * - `@file:path` - Reads content from an external file\n * - `@url:address` - Fetches content from a URL\n * - `@lookup:Entity.Field=Value` - Looks up an entity ID by field value\n * - `@env:VARIABLE` - Reads an environment variable\n * \n * @param value - The field value to process\n * @param baseDir - Base directory for resolving relative file paths\n * @param parentRecord - Optional parent entity for @parent references\n * @param rootRecord - Optional root entity for @root references\n * @returns The processed value with all references resolved\n * @throws Error if a reference cannot be resolved\n * \n * @example\n * ```typescript\n * // File reference\n * const content = await processFieldValue('@file:template.md', '/path/to/dir');\n * \n * // Lookup with auto-create\n * const userId = await processFieldValue('@lookup:Users.Email=john@example.com?create', '/path');\n * ```\n */\n async processFieldValue(value: any, baseDir: string, parentRecord?: BaseEntity | null, rootRecord?: BaseEntity | null): Promise<any> {\n if (typeof value !== 'string') {\n return value;\n }\n \n // Check for @parent: reference\n if (value.startsWith('@parent:')) {\n if (!parentRecord) {\n throw new Error(`@parent reference used but no parent record available: ${value}`);\n }\n const fieldName = value.substring(8);\n return parentRecord.Get(fieldName);\n }\n \n // Check for @root: reference\n if (value.startsWith('@root:')) {\n if (!rootRecord) {\n throw new Error(`@root reference used but no root record available: ${value}`);\n }\n const fieldName = value.substring(6);\n return rootRecord.Get(fieldName);\n }\n \n // Check for @file: reference\n if (value.startsWith('@file:')) {\n const filePath = value.substring(6);\n const fullPath = path.resolve(baseDir, filePath);\n \n if (await fs.pathExists(fullPath)) {\n return await fs.readFile(fullPath, 'utf-8');\n } else {\n throw new Error(`File not found: ${fullPath}`);\n }\n }\n \n // Check for @url: reference\n if (value.startsWith('@url:')) {\n const url = value.substring(5);\n \n try {\n const response = await axios.get(url);\n return response.data;\n } catch (error) {\n throw new Error(`Failed to fetch URL: ${url} - ${error}`);\n }\n }\n \n // Check for @lookup: reference\n if (value.startsWith('@lookup:')) {\n const lookupStr = value.substring(8);\n \n // Parse lookup with optional create syntax\n // Format: EntityName.Field1=Value1&Field2=Value2?create&OtherField=Value\n const entityMatch = lookupStr.match(/^([^.]+)\\./);\n if (!entityMatch) {\n throw new Error(`Invalid lookup format: ${value}`);\n }\n \n const entityName = entityMatch[1];\n const remaining = lookupStr.substring(entityName.length + 1);\n \n // Check if this has ?create syntax\n const hasCreate = remaining.includes('?create');\n const lookupPart = hasCreate ? remaining.split('?')[0] : remaining;\n \n // Parse all lookup fields (can be multiple with &)\n const lookupFields: Array<{fieldName: string, fieldValue: string}> = [];\n const lookupPairs = lookupPart.split('&');\n \n for (const pair of lookupPairs) {\n const fieldMatch = pair.match(/^(.+?)=(.+)$/);\n if (!fieldMatch) {\n throw new Error(`Invalid lookup field format: ${pair} in ${value}`);\n }\n const [, fieldName, fieldValue] = fieldMatch;\n lookupFields.push({ fieldName: fieldName.trim(), fieldValue: fieldValue.trim() });\n }\n \n if (lookupFields.length === 0) {\n throw new Error(`No lookup fields specified: ${value}`);\n }\n \n // Parse additional fields for creation if ?create is present\n let createFields: Record<string, any> = {};\n if (hasCreate && remaining.includes('?create&')) {\n const createPart = remaining.split('?create&')[1];\n const pairs = createPart.split('&');\n for (const pair of pairs) {\n const [key, val] = pair.split('=');\n if (key && val) {\n createFields[key] = decodeURIComponent(val);\n }\n }\n }\n \n return await this.resolveLookup(entityName, lookupFields, hasCreate, createFields);\n }\n \n // Check for @env: reference\n if (value.startsWith('@env:')) {\n const envVar = value.substring(5);\n const envValue = process.env[envVar];\n \n if (envValue === undefined) {\n throw new Error(`Environment variable not found: ${envVar}`);\n }\n \n return envValue;\n }\n \n return value;\n }\n \n /**\n * Resolve a lookup reference to an ID, optionally creating the record if it doesn't exist\n * \n * @param entityName - Name of the entity to search in\n * @param fieldName - Field to match against\n * @param fieldValue - Value to search for\n * @param autoCreate - Whether to create the record if not found\n * @param createFields - Additional fields to set when creating\n * @returns The ID of the found or created record\n * @throws Error if lookup fails and autoCreate is false\n * \n * @example\n * ```typescript\n * // Simple lookup\n * const categoryId = await resolveLookup('Categories', 'Name', 'Technology');\n * \n * // Lookup with auto-create\n * const tagId = await resolveLookup('Tags', 'Name', 'New Tag', true, {\n * Description: 'Auto-created tag',\n * Status: 'Active'\n * });\n * ```\n */\n async resolveLookup(\n entityName: string, \n lookupFields: Array<{fieldName: string, fieldValue: string}>,\n autoCreate: boolean = false,\n createFields: Record<string, any> = {}\n ): Promise<string> {\n // Debug logging handled by caller if needed\n \n const rv = new RunView();\n const entityInfo = this.metadata.EntityByName(entityName);\n if (!entityInfo) {\n throw new Error(`Entity not found: ${entityName}`);\n }\n \n // Build compound filter for all lookup fields\n const filterParts: string[] = [];\n for (const {fieldName, fieldValue} of lookupFields) {\n const field = entityInfo.Fields.find(f => f.Name.trim().toLowerCase() === fieldName.trim().toLowerCase());\n if (!field) {\n throw new Error(`Field '${fieldName}' not found in entity '${entityName}'`);\n }\n \n // Handle null values properly\n if (fieldValue.trim().toLowerCase() === 'null') {\n filterParts.push(`${fieldName} IS NULL`);\n } else {\n const quotes = field.NeedsQuotes ? \"'\" : '';\n filterParts.push(`${fieldName} = ${quotes}${fieldValue.replace(/'/g, \"''\")}${quotes}`);\n }\n }\n \n const extraFilter = filterParts.join(' AND ');\n const result = await rv.RunView({\n EntityName: entityName,\n ExtraFilter: extraFilter,\n MaxRows: 1\n }, this.contextUser);\n \n if (result.Success && result.Results.length > 0) {\n if (entityInfo.PrimaryKeys.length > 0) {\n const pkeyField = entityInfo.PrimaryKeys[0].Name;\n const id = result.Results[0][pkeyField];\n return id;\n }\n }\n \n // If not found and auto-create is enabled, create the record\n if (autoCreate) {\n \n const newEntity = await this.metadata.GetEntityObject(entityName, this.contextUser);\n if (!newEntity) {\n throw new Error(`Failed to create entity object for: ${entityName}`);\n }\n \n newEntity.NewRecord();\n \n // Handle explicit ID setting for new records\n if (entityInfo.PrimaryKeys.length > 0) {\n for (const pk of entityInfo.PrimaryKeys) {\n if (!pk.AutoIncrement && pk.Type.toLowerCase() === 'uniqueidentifier') {\n // Generate UUID for this primary key and set it explicitly\n const uuid = uuidv4();\n (newEntity as any)[pk.Name] = uuid;\n }\n }\n }\n \n // Set all lookup fields\n for (const {fieldName, fieldValue} of lookupFields) {\n if (fieldName in newEntity) {\n // Handle null values properly\n if (fieldValue.toLowerCase() === 'null') {\n (newEntity as any)[fieldName] = null;\n } else {\n (newEntity as any)[fieldName] = fieldValue;\n }\n }\n }\n \n // Set any additional fields provided\n for (const [key, value] of Object.entries(createFields)) {\n if (key in newEntity) {\n (newEntity as any)[key] = value;\n }\n }\n \n // Save the new record (new records are always dirty)\n const filterDesc = lookupFields.map(({fieldName, fieldValue}) => `${fieldName}='${fieldValue}'`).join(' AND ');\n console.log(`📝 Auto-creating ${entityName} record where ${filterDesc}`);\n const saved = await newEntity.Save();\n if (!saved) {\n const message = newEntity.LatestResult?.Message;\n if (message) {\n throw new Error(`Failed to auto-create ${entityName}: ${message}`);\n }\n \n const errors = newEntity.LatestResult?.Errors?.map(err => \n typeof err === 'string' ? err : (err?.message || JSON.stringify(err))\n )?.join(', ') || 'Unknown error';\n throw new Error(`Failed to auto-create ${entityName}: ${errors}`);\n }\n \n // Return the new ID\n if (entityInfo.PrimaryKeys.length > 0) {\n const pkeyField = entityInfo.PrimaryKeys[0].Name;\n const newId = newEntity.Get(pkeyField);\n return newId;\n }\n }\n \n const filterDesc = lookupFields.map(({fieldName, fieldValue}) => `${fieldName}='${fieldValue}'`).join(' AND ');\n throw new Error(`Lookup failed: No record found in '${entityName}' where ${filterDesc}`);\n }\n \n /**\n * Build cascading defaults for a file path and process field values\n * \n * Walks up the directory tree from the file location, collecting defaults from\n * entity config and folder configs, with deeper folders overriding parent values.\n * All default values are processed for special references.\n * \n * @param filePath - Path to the file being processed\n * @param entityConfig - Entity configuration containing base defaults\n * @returns Processed defaults with all references resolved\n * @throws Error if any default value processing fails\n */\n async buildDefaults(filePath: string, entityConfig: EntityConfig): Promise<Record<string, any>> {\n const parts = path.dirname(filePath).split(path.sep);\n let defaults: Record<string, any> = { ...entityConfig.defaults };\n \n // Walk up the directory tree building defaults\n let currentPath = '';\n for (const part of parts) {\n currentPath = path.join(currentPath, part);\n const folderConfig = await this.loadFolderConfig(currentPath);\n \n if (folderConfig?.defaults) {\n defaults = { ...defaults, ...folderConfig.defaults };\n }\n }\n \n // Process all default values (lookups, file references, etc.)\n const processedDefaults: Record<string, any> = {};\n const baseDir = path.dirname(filePath);\n \n for (const [field, value] of Object.entries(defaults)) {\n try {\n processedDefaults[field] = await this.processFieldValue(value, baseDir, null, null);\n } catch (error) {\n throw new Error(`Failed to process default for field '${field}': ${error}`);\n }\n }\n \n return processedDefaults;\n }\n \n /**\n * Load folder configuration from .mj-folder.json file\n * \n * @param dir - Directory to check for configuration\n * @returns Folder configuration or null if not found/invalid\n * @private\n */\n private async loadFolderConfig(dir: string): Promise<FolderConfig | null> {\n const configPath = path.join(dir, '.mj-folder.json');\n \n if (await fs.pathExists(configPath)) {\n try {\n return await fs.readJson(configPath);\n } catch (error) {\n console.error(`Error loading folder config at ${configPath}:`, error);\n return null;\n }\n }\n \n return null;\n }\n \n /**\n * Calculate SHA256 checksum for data\n * \n * Generates a deterministic hash of the provided data by converting it to\n * formatted JSON and calculating a SHA256 digest. Used for change detection\n * in sync operations.\n * \n * @param data - Any data structure to calculate checksum for\n * @returns Hexadecimal string representation of the SHA256 hash\n * \n * @example\n * ```typescript\n * const checksum = syncEngine.calculateChecksum({\n * name: 'Test Record',\n * value: 42,\n * tags: ['a', 'b']\n * });\n * // Returns consistent hash for same data structure\n * ```\n */\n calculateChecksum(data: any): string {\n const hash = crypto.createHash('sha256');\n hash.update(JSON.stringify(data, null, 2));\n return hash.digest('hex');\n }\n \n /**\n * Get entity metadata information by name\n * \n * Retrieves the EntityInfo object containing schema metadata for the specified entity.\n * Returns null if the entity is not found in the metadata cache.\n * \n * @param entityName - Name of the entity to look up\n * @returns EntityInfo object with schema details or null if not found\n * \n * @example\n * ```typescript\n * const entityInfo = syncEngine.getEntityInfo('AI Prompts');\n * if (entityInfo) {\n * console.log(`Primary keys: ${entityInfo.PrimaryKeys.map(pk => pk.Name).join(', ')}`);\n * }\n * ```\n */\n getEntityInfo(entityName: string): EntityInfo | null {\n return this.metadata.EntityByName(entityName);\n }\n \n /**\n * Create a new entity object instance\n * \n * Uses the MemberJunction metadata system to properly instantiate an entity object.\n * This ensures correct class registration and respects any custom entity subclasses.\n * \n * @param entityName - Name of the entity to create\n * @returns Promise resolving to the new BaseEntity instance\n * @throws Error if entity creation fails\n * \n * @example\n * ```typescript\n * const entity = await syncEngine.createEntityObject('AI Prompts');\n * entity.NewRecord();\n * entity.Set('Name', 'My Prompt');\n * await entity.Save();\n * ```\n */\n async createEntityObject(entityName: string): Promise<BaseEntity> {\n const entity = await this.metadata.GetEntityObject(entityName, this.contextUser);\n if (!entity) {\n throw new Error(`Failed to create entity object for: ${entityName}`);\n }\n return entity;\n }\n \n /**\n * Load an entity record by primary key\n * \n * Retrieves an existing entity record from the database using its primary key values.\n * Supports both single and composite primary keys. Returns null if the record is not found.\n * \n * @param entityName - Name of the entity to load\n * @param primaryKey - Object containing primary key field names and values\n * @returns Promise resolving to the loaded entity or null if not found\n * @throws Error if entity metadata is not found\n * \n * @example\n * ```typescript\n * // Single primary key\n * const entity = await syncEngine.loadEntity('Users', { ID: '123-456' });\n * \n * // Composite primary key\n * const entity = await syncEngine.loadEntity('UserRoles', { \n * UserID: '123-456',\n * RoleID: '789-012'\n * });\n * ```\n */\n async loadEntity(entityName: string, primaryKey: Record<string, any>): Promise<BaseEntity | null> {\n const entityInfo = this.getEntityInfo(entityName);\n \n if (!entityInfo) {\n throw new Error(`Entity not found: ${entityName}`);\n }\n \n // First, check if the record exists using RunView to avoid \"Error in BaseEntity.Load\" messages\n // when records don't exist (which is a normal scenario during sync operations)\n const rv = new RunView();\n \n // Build filter for primary key(s)\n const filters: string[] = [];\n for (const pk of entityInfo.PrimaryKeys) {\n const value = primaryKey[pk.Name];\n if (value === undefined || value === null) {\n throw new Error(`Missing primary key value for ${pk.Name} in entity ${entityName}`);\n }\n \n // Check if field needs quotes\n const field = entityInfo.Fields.find(f => f.Name === pk.Name);\n const quotes = field?.NeedsQuotes ? \"'\" : '';\n const escapedValue = field?.NeedsQuotes && typeof value === 'string' ? value.replace(/'/g, \"''\") : value;\n filters.push(`${pk.Name} = ${quotes}${escapedValue}${quotes}`);\n }\n \n const result = await rv.RunView({\n EntityName: entityName,\n ExtraFilter: filters.join(' AND '),\n MaxRows: 1\n }, this.contextUser);\n \n // If no record found, return null without attempting to load\n if (!result.Success || result.Results.length === 0) {\n return null;\n }\n \n // Record exists, now load it properly through the entity\n const entity = await this.createEntityObject(entityName);\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromSimpleObject(primaryKey);\n const loaded = await entity.InnerLoad(compositeKey);\n \n return loaded ? entity : null;\n }\n \n /**\n * Process JSON object with template references\n * \n * Recursively processes JSON data structures to resolve `@template` references.\n * Templates can be defined at any level and support:\n * - Single template references: `\"@template:path/to/template.json\"`\n * - Object with @template field: `{ \"@template\": \"file.json\", \"override\": \"value\" }`\n * - Array of templates for merging: `{ \"@template\": [\"base.json\", \"overrides.json\"] }`\n * - Nested template references within templates\n * \n * @param data - JSON data structure to process\n * @param baseDir - Base directory for resolving relative template paths\n * @returns Promise resolving to the processed data with all templates resolved\n * @throws Error if template file is not found or contains invalid JSON\n * \n * @example\n * ```typescript\n * // Input data with template reference\n * const data = {\n * \"@template\": \"defaults/ai-prompt.json\",\n * \"Name\": \"Custom Prompt\",\n * \"Prompt\": \"Override the template prompt\"\n * };\n * \n * // Resolves template and merges with overrides\n * const result = await syncEngine.processTemplates(data, '/path/to/dir');\n * ```\n */\n async processTemplates(data: any, baseDir: string): Promise<any> {\n // Handle arrays\n if (Array.isArray(data)) {\n const processedArray = [];\n for (const item of data) {\n processedArray.push(await this.processTemplates(item, baseDir));\n }\n return processedArray;\n }\n \n // Handle objects\n if (data && typeof data === 'object') {\n // Check for @template reference\n if (typeof data === 'string' && data.startsWith('@template:')) {\n const templatePath = data.substring(10);\n return await this.loadAndProcessTemplate(templatePath, baseDir);\n }\n \n // Process object with possible @template field\n const processed: any = {};\n let templateData: any = {};\n \n // First, check if there's a @template field to process\n if (data['@template']) {\n const templates = Array.isArray(data['@template']) ? data['@template'] : [data['@template']];\n \n // Process templates in order, merging them\n for (const templateRef of templates) {\n const templateContent = await this.loadAndProcessTemplate(templateRef, baseDir);\n templateData = this.deepMerge(templateData, templateContent);\n }\n }\n \n // Process all other fields\n for (const [key, value] of Object.entries(data)) {\n if (key === '@template') continue; // Skip the template field itself\n \n // Process the value recursively\n processed[key] = await this.processTemplates(value, baseDir);\n }\n \n // Merge template data with processed data (processed data takes precedence)\n return this.deepMerge(templateData, processed);\n }\n \n // Return primitive values as-is\n return data;\n }\n \n /**\n * Load and process a template file\n * \n * Loads a JSON template file from the filesystem and recursively processes any\n * nested template references within it. Template paths are resolved relative to\n * the template file's directory, enabling template composition.\n * \n * @param templatePath - Path to the template file (relative or absolute)\n * @param baseDir - Base directory for resolving relative paths\n * @returns Promise resolving to the processed template content\n * @throws Error if template file not found or contains invalid JSON\n * @private\n */\n private async loadAndProcessTemplate(templatePath: string, baseDir: string): Promise<any> {\n const fullPath = path.resolve(baseDir, templatePath);\n \n if (!await fs.pathExists(fullPath)) {\n throw new Error(`Template file not found: ${fullPath}`);\n }\n \n try {\n const templateContent = await fs.readJson(fullPath);\n \n // Recursively process any nested templates\n const templateDir = path.dirname(fullPath);\n return await this.processTemplates(templateContent, templateDir);\n } catch (error) {\n throw new Error(`Failed to load template ${fullPath}: ${error}`);\n }\n }\n \n /**\n * Deep merge two objects with target taking precedence\n * \n * Recursively merges two objects, with values from the target object overriding\n * values from the source object. Arrays and primitive values are not merged but\n * replaced entirely by the target value. Undefined values in target are skipped.\n * \n * @param source - Base object to merge from\n * @param target - Object with values that override source\n * @returns New object with merged values\n * @private\n * \n * @example\n * ```typescript\n * const source = {\n * a: 1,\n * b: { x: 10, y: 20 },\n * c: [1, 2, 3]\n * };\n * const target = {\n * a: 2,\n * b: { y: 30, z: 40 },\n * d: 'new'\n * };\n * const result = deepMerge(source, target);\n * // Result: { a: 2, b: { x: 10, y: 30, z: 40 }, c: [1, 2, 3], d: 'new' }\n * ```\n */\n private deepMerge(source: any, target: any): any {\n if (!source) return target;\n if (!target) return source;\n \n // If target is not an object, it completely overrides source\n if (typeof target !== 'object' || target === null || Array.isArray(target)) {\n return target;\n }\n \n // If source is not an object, target wins\n if (typeof source !== 'object' || source === null || Array.isArray(source)) {\n return target;\n }\n \n // Both are objects, merge them\n const result: any = { ...source };\n \n for (const [key, value] of Object.entries(target)) {\n if (value === undefined) {\n continue; // Skip undefined values\n }\n \n if (typeof value === 'object' && value !== null && !Array.isArray(value) &&\n typeof result[key] === 'object' && result[key] !== null && !Array.isArray(result[key])) {\n // Both are objects, merge recursively\n result[key] = this.deepMerge(result[key], value);\n } else {\n // Otherwise, target value wins\n result[key] = value;\n }\n }\n \n return result;\n }\n \n}"]}
1
+ {"version":3,"file":"sync-engine.js","sourceRoot":"","sources":["../../src/lib/sync-engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Core synchronization engine for MemberJunction metadata\n * @module sync-engine\n * \n * This module provides the core functionality for synchronizing metadata between\n * the MemberJunction database and local file system representations. It handles\n * special reference types (@file, @url, @lookup, @env, @parent, @root, @template),\n * manages entity operations, and provides utilities for data transformation.\n */\n\nimport path from 'path';\nimport fs from 'fs-extra';\nimport crypto from 'crypto';\nimport axios from 'axios';\nimport { EntityInfo, Metadata, RunView, BaseEntity, CompositeKey, UserInfo } from '@memberjunction/core';\nimport { uuidv4 } from '@memberjunction/global';\nimport { EntityConfig, FolderConfig } from '../config';\n\n/**\n * Represents the structure of a metadata record with optional sync tracking\n */\nexport interface RecordData {\n /** Primary key field(s) and their values */\n primaryKey?: Record<string, any>;\n /** Entity field names and their values */\n fields: Record<string, any>;\n /** Related entities organized by entity name */\n relatedEntities?: Record<string, RecordData[]>;\n /** Synchronization metadata for change tracking */\n sync?: {\n /** ISO timestamp of last modification */\n lastModified: string;\n /** SHA256 checksum of the fields object */\n checksum: string;\n };\n}\n\n/**\n * Core engine for synchronizing MemberJunction metadata between database and files\n * \n * @class SyncEngine\n * @example\n * ```typescript\n * const syncEngine = new SyncEngine(systemUser);\n * await syncEngine.initialize();\n * \n * // Process a field value with special references\n * const value = await syncEngine.processFieldValue('@lookup:Users.Email=admin@example.com', '/path/to/base');\n * ```\n */\nexport class SyncEngine {\n private metadata: Metadata;\n private contextUser: UserInfo;\n\n /**\n * Creates a new SyncEngine instance\n * @param contextUser - The user context for database operations\n */\n constructor(contextUser: UserInfo) {\n this.metadata = new Metadata();\n this.contextUser = contextUser;\n }\n \n /**\n * Initializes the sync engine by refreshing metadata cache\n * @returns Promise that resolves when initialization is complete\n */\n async initialize(forceRefresh: boolean = false): Promise<void> {\n if (forceRefresh) {\n await this.metadata.Refresh();\n }\n }\n \n /**\n * Process special references in field values\n * \n * Handles the following reference types:\n * - `@parent:fieldName` - References a field from the parent record\n * - `@root:fieldName` - References a field from the root record\n * - `@file:path` - Reads content from an external file\n * - `@url:address` - Fetches content from a URL\n * - `@lookup:Entity.Field=Value` - Looks up an entity ID by field value\n * - `@env:VARIABLE` - Reads an environment variable\n * \n * @param value - The field value to process\n * @param baseDir - Base directory for resolving relative file paths\n * @param parentRecord - Optional parent entity for @parent references\n * @param rootRecord - Optional root entity for @root references\n * @returns The processed value with all references resolved\n * @throws Error if a reference cannot be resolved\n * \n * @example\n * ```typescript\n * // File reference\n * const content = await processFieldValue('@file:template.md', '/path/to/dir');\n * \n * // Lookup with auto-create\n * const userId = await processFieldValue('@lookup:Users.Email=john@example.com?create', '/path');\n * ```\n */\n async processFieldValue(value: any, baseDir: string, parentRecord?: BaseEntity | null, rootRecord?: BaseEntity | null): Promise<any> {\n if (typeof value !== 'string') {\n return value;\n }\n \n // Check for @parent: reference\n if (value.startsWith('@parent:')) {\n if (!parentRecord) {\n throw new Error(`@parent reference used but no parent record available: ${value}`);\n }\n const fieldName = value.substring(8);\n return parentRecord.Get(fieldName);\n }\n \n // Check for @root: reference\n if (value.startsWith('@root:')) {\n if (!rootRecord) {\n throw new Error(`@root reference used but no root record available: ${value}`);\n }\n const fieldName = value.substring(6);\n return rootRecord.Get(fieldName);\n }\n \n // Check for @file: reference\n if (value.startsWith('@file:')) {\n const filePath = value.substring(6);\n const fullPath = path.resolve(baseDir, filePath);\n \n if (await fs.pathExists(fullPath)) {\n const fileContent = await fs.readFile(fullPath, 'utf-8');\n \n // Process the file content for {@include} references\n return await this.processFileContentWithIncludes(fullPath, fileContent);\n } else {\n throw new Error(`File not found: ${fullPath}`);\n }\n }\n \n // Check for @url: reference\n if (value.startsWith('@url:')) {\n const url = value.substring(5);\n \n try {\n const response = await axios.get(url);\n return response.data;\n } catch (error) {\n throw new Error(`Failed to fetch URL: ${url} - ${error}`);\n }\n }\n \n // Check for @lookup: reference\n if (value.startsWith('@lookup:')) {\n const lookupStr = value.substring(8);\n \n // Parse lookup with optional create syntax\n // Format: EntityName.Field1=Value1&Field2=Value2?create&OtherField=Value\n const entityMatch = lookupStr.match(/^([^.]+)\\./);\n if (!entityMatch) {\n throw new Error(`Invalid lookup format: ${value}`);\n }\n \n const entityName = entityMatch[1];\n const remaining = lookupStr.substring(entityName.length + 1);\n \n // Check if this has ?create syntax\n const hasCreate = remaining.includes('?create');\n const lookupPart = hasCreate ? remaining.split('?')[0] : remaining;\n \n // Parse all lookup fields (can be multiple with &)\n const lookupFields: Array<{fieldName: string, fieldValue: string}> = [];\n const lookupPairs = lookupPart.split('&');\n \n for (const pair of lookupPairs) {\n const fieldMatch = pair.match(/^(.+?)=(.+)$/);\n if (!fieldMatch) {\n throw new Error(`Invalid lookup field format: ${pair} in ${value}`);\n }\n const [, fieldName, fieldValue] = fieldMatch;\n lookupFields.push({ fieldName: fieldName.trim(), fieldValue: fieldValue.trim() });\n }\n \n if (lookupFields.length === 0) {\n throw new Error(`No lookup fields specified: ${value}`);\n }\n \n // Parse additional fields for creation if ?create is present\n let createFields: Record<string, any> = {};\n if (hasCreate && remaining.includes('?create&')) {\n const createPart = remaining.split('?create&')[1];\n const pairs = createPart.split('&');\n for (const pair of pairs) {\n const [key, val] = pair.split('=');\n if (key && val) {\n createFields[key] = decodeURIComponent(val);\n }\n }\n }\n \n return await this.resolveLookup(entityName, lookupFields, hasCreate, createFields);\n }\n \n // Check for @env: reference\n if (value.startsWith('@env:')) {\n const envVar = value.substring(5);\n const envValue = process.env[envVar];\n \n if (envValue === undefined) {\n throw new Error(`Environment variable not found: ${envVar}`);\n }\n \n return envValue;\n }\n \n return value;\n }\n \n /**\n * Resolve a lookup reference to an ID, optionally creating the record if it doesn't exist\n * \n * @param entityName - Name of the entity to search in\n * @param fieldName - Field to match against\n * @param fieldValue - Value to search for\n * @param autoCreate - Whether to create the record if not found\n * @param createFields - Additional fields to set when creating\n * @returns The ID of the found or created record\n * @throws Error if lookup fails and autoCreate is false\n * \n * @example\n * ```typescript\n * // Simple lookup\n * const categoryId = await resolveLookup('Categories', 'Name', 'Technology');\n * \n * // Lookup with auto-create\n * const tagId = await resolveLookup('Tags', 'Name', 'New Tag', true, {\n * Description: 'Auto-created tag',\n * Status: 'Active'\n * });\n * ```\n */\n async resolveLookup(\n entityName: string, \n lookupFields: Array<{fieldName: string, fieldValue: string}>,\n autoCreate: boolean = false,\n createFields: Record<string, any> = {}\n ): Promise<string> {\n // Debug logging handled by caller if needed\n \n const rv = new RunView();\n const entityInfo = this.metadata.EntityByName(entityName);\n if (!entityInfo) {\n throw new Error(`Entity not found: ${entityName}`);\n }\n \n // Build compound filter for all lookup fields\n const filterParts: string[] = [];\n for (const {fieldName, fieldValue} of lookupFields) {\n const field = entityInfo.Fields.find(f => f.Name.trim().toLowerCase() === fieldName.trim().toLowerCase());\n if (!field) {\n throw new Error(`Field '${fieldName}' not found in entity '${entityName}'`);\n }\n \n // Handle null values properly\n if (fieldValue.trim().toLowerCase() === 'null') {\n filterParts.push(`${fieldName} IS NULL`);\n } else {\n const quotes = field.NeedsQuotes ? \"'\" : '';\n filterParts.push(`${fieldName} = ${quotes}${fieldValue.replace(/'/g, \"''\")}${quotes}`);\n }\n }\n \n const extraFilter = filterParts.join(' AND ');\n const result = await rv.RunView({\n EntityName: entityName,\n ExtraFilter: extraFilter,\n MaxRows: 1\n }, this.contextUser);\n \n if (result.Success && result.Results.length > 0) {\n if (entityInfo.PrimaryKeys.length > 0) {\n const pkeyField = entityInfo.PrimaryKeys[0].Name;\n const id = result.Results[0][pkeyField];\n return id;\n }\n }\n \n // If not found and auto-create is enabled, create the record\n if (autoCreate) {\n \n const newEntity = await this.metadata.GetEntityObject(entityName, this.contextUser);\n if (!newEntity) {\n throw new Error(`Failed to create entity object for: ${entityName}`);\n }\n \n newEntity.NewRecord();\n \n // Handle explicit ID setting for new records\n if (entityInfo.PrimaryKeys.length > 0) {\n for (const pk of entityInfo.PrimaryKeys) {\n if (!pk.AutoIncrement && pk.Type.toLowerCase() === 'uniqueidentifier') {\n // Generate UUID for this primary key and set it explicitly\n const uuid = uuidv4();\n (newEntity as any)[pk.Name] = uuid;\n }\n }\n }\n \n // Set all lookup fields\n for (const {fieldName, fieldValue} of lookupFields) {\n if (fieldName in newEntity) {\n // Handle null values properly\n if (fieldValue.toLowerCase() === 'null') {\n (newEntity as any)[fieldName] = null;\n } else {\n (newEntity as any)[fieldName] = fieldValue;\n }\n }\n }\n \n // Set any additional fields provided\n for (const [key, value] of Object.entries(createFields)) {\n if (key in newEntity) {\n (newEntity as any)[key] = value;\n }\n }\n \n // Save the new record (new records are always dirty)\n const filterDesc = lookupFields.map(({fieldName, fieldValue}) => `${fieldName}='${fieldValue}'`).join(' AND ');\n console.log(`📝 Auto-creating ${entityName} record where ${filterDesc}`);\n const saved = await newEntity.Save();\n if (!saved) {\n const message = newEntity.LatestResult?.Message;\n if (message) {\n throw new Error(`Failed to auto-create ${entityName}: ${message}`);\n }\n \n const errors = newEntity.LatestResult?.Errors?.map(err => \n typeof err === 'string' ? err : (err?.message || JSON.stringify(err))\n )?.join(', ') || 'Unknown error';\n throw new Error(`Failed to auto-create ${entityName}: ${errors}`);\n }\n \n // Return the new ID\n if (entityInfo.PrimaryKeys.length > 0) {\n const pkeyField = entityInfo.PrimaryKeys[0].Name;\n const newId = newEntity.Get(pkeyField);\n return newId;\n }\n }\n \n const filterDesc = lookupFields.map(({fieldName, fieldValue}) => `${fieldName}='${fieldValue}'`).join(' AND ');\n throw new Error(`Lookup failed: No record found in '${entityName}' where ${filterDesc}`);\n }\n \n /**\n * Build cascading defaults for a file path and process field values\n * \n * Walks up the directory tree from the file location, collecting defaults from\n * entity config and folder configs, with deeper folders overriding parent values.\n * All default values are processed for special references.\n * \n * @param filePath - Path to the file being processed\n * @param entityConfig - Entity configuration containing base defaults\n * @returns Processed defaults with all references resolved\n * @throws Error if any default value processing fails\n */\n async buildDefaults(filePath: string, entityConfig: EntityConfig): Promise<Record<string, any>> {\n const parts = path.dirname(filePath).split(path.sep);\n let defaults: Record<string, any> = { ...entityConfig.defaults };\n \n // Walk up the directory tree building defaults\n let currentPath = '';\n for (const part of parts) {\n currentPath = path.join(currentPath, part);\n const folderConfig = await this.loadFolderConfig(currentPath);\n \n if (folderConfig?.defaults) {\n defaults = { ...defaults, ...folderConfig.defaults };\n }\n }\n \n // Process all default values (lookups, file references, etc.)\n const processedDefaults: Record<string, any> = {};\n const baseDir = path.dirname(filePath);\n \n for (const [field, value] of Object.entries(defaults)) {\n try {\n processedDefaults[field] = await this.processFieldValue(value, baseDir, null, null);\n } catch (error) {\n throw new Error(`Failed to process default for field '${field}': ${error}`);\n }\n }\n \n return processedDefaults;\n }\n \n /**\n * Load folder configuration from .mj-folder.json file\n * \n * @param dir - Directory to check for configuration\n * @returns Folder configuration or null if not found/invalid\n * @private\n */\n private async loadFolderConfig(dir: string): Promise<FolderConfig | null> {\n const configPath = path.join(dir, '.mj-folder.json');\n \n if (await fs.pathExists(configPath)) {\n try {\n return await fs.readJson(configPath);\n } catch (error) {\n console.error(`Error loading folder config at ${configPath}:`, error);\n return null;\n }\n }\n \n return null;\n }\n \n /**\n * Calculate SHA256 checksum for data\n * \n * Generates a deterministic hash of the provided data by converting it to\n * formatted JSON and calculating a SHA256 digest. Used for change detection\n * in sync operations.\n * \n * @param data - Any data structure to calculate checksum for\n * @returns Hexadecimal string representation of the SHA256 hash\n * \n * @example\n * ```typescript\n * const checksum = syncEngine.calculateChecksum({\n * name: 'Test Record',\n * value: 42,\n * tags: ['a', 'b']\n * });\n * // Returns consistent hash for same data structure\n * ```\n */\n calculateChecksum(data: any): string {\n const hash = crypto.createHash('sha256');\n hash.update(JSON.stringify(data, null, 2));\n return hash.digest('hex');\n }\n \n /**\n * Get entity metadata information by name\n * \n * Retrieves the EntityInfo object containing schema metadata for the specified entity.\n * Returns null if the entity is not found in the metadata cache.\n * \n * @param entityName - Name of the entity to look up\n * @returns EntityInfo object with schema details or null if not found\n * \n * @example\n * ```typescript\n * const entityInfo = syncEngine.getEntityInfo('AI Prompts');\n * if (entityInfo) {\n * console.log(`Primary keys: ${entityInfo.PrimaryKeys.map(pk => pk.Name).join(', ')}`);\n * }\n * ```\n */\n getEntityInfo(entityName: string): EntityInfo | null {\n return this.metadata.EntityByName(entityName);\n }\n \n /**\n * Create a new entity object instance\n * \n * Uses the MemberJunction metadata system to properly instantiate an entity object.\n * This ensures correct class registration and respects any custom entity subclasses.\n * \n * @param entityName - Name of the entity to create\n * @returns Promise resolving to the new BaseEntity instance\n * @throws Error if entity creation fails\n * \n * @example\n * ```typescript\n * const entity = await syncEngine.createEntityObject('AI Prompts');\n * entity.NewRecord();\n * entity.Set('Name', 'My Prompt');\n * await entity.Save();\n * ```\n */\n async createEntityObject(entityName: string): Promise<BaseEntity> {\n const entity = await this.metadata.GetEntityObject(entityName, this.contextUser);\n if (!entity) {\n throw new Error(`Failed to create entity object for: ${entityName}`);\n }\n return entity;\n }\n \n /**\n * Load an entity record by primary key\n * \n * Retrieves an existing entity record from the database using its primary key values.\n * Supports both single and composite primary keys. Returns null if the record is not found.\n * \n * @param entityName - Name of the entity to load\n * @param primaryKey - Object containing primary key field names and values\n * @returns Promise resolving to the loaded entity or null if not found\n * @throws Error if entity metadata is not found\n * \n * @example\n * ```typescript\n * // Single primary key\n * const entity = await syncEngine.loadEntity('Users', { ID: '123-456' });\n * \n * // Composite primary key\n * const entity = await syncEngine.loadEntity('UserRoles', { \n * UserID: '123-456',\n * RoleID: '789-012'\n * });\n * ```\n */\n async loadEntity(entityName: string, primaryKey: Record<string, any>): Promise<BaseEntity | null> {\n const entityInfo = this.getEntityInfo(entityName);\n \n if (!entityInfo) {\n throw new Error(`Entity not found: ${entityName}`);\n }\n \n // First, check if the record exists using RunView to avoid \"Error in BaseEntity.Load\" messages\n // when records don't exist (which is a normal scenario during sync operations)\n const rv = new RunView();\n \n // Build filter for primary key(s)\n const filters: string[] = [];\n for (const pk of entityInfo.PrimaryKeys) {\n const value = primaryKey[pk.Name];\n if (value === undefined || value === null) {\n throw new Error(`Missing primary key value for ${pk.Name} in entity ${entityName}`);\n }\n \n // Check if field needs quotes\n const field = entityInfo.Fields.find(f => f.Name === pk.Name);\n const quotes = field?.NeedsQuotes ? \"'\" : '';\n const escapedValue = field?.NeedsQuotes && typeof value === 'string' ? value.replace(/'/g, \"''\") : value;\n filters.push(`${pk.Name} = ${quotes}${escapedValue}${quotes}`);\n }\n \n const result = await rv.RunView({\n EntityName: entityName,\n ExtraFilter: filters.join(' AND '),\n MaxRows: 1\n }, this.contextUser);\n \n // If no record found, return null without attempting to load\n if (!result.Success || result.Results.length === 0) {\n return null;\n }\n \n // Record exists, now load it properly through the entity\n const entity = await this.createEntityObject(entityName);\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromSimpleObject(primaryKey);\n const loaded = await entity.InnerLoad(compositeKey);\n \n return loaded ? entity : null;\n }\n \n /**\n * Process JSON object with template references\n * \n * Recursively processes JSON data structures to resolve `@template` references.\n * Templates can be defined at any level and support:\n * - Single template references: `\"@template:path/to/template.json\"`\n * - Object with @template field: `{ \"@template\": \"file.json\", \"override\": \"value\" }`\n * - Array of templates for merging: `{ \"@template\": [\"base.json\", \"overrides.json\"] }`\n * - Nested template references within templates\n * \n * @param data - JSON data structure to process\n * @param baseDir - Base directory for resolving relative template paths\n * @returns Promise resolving to the processed data with all templates resolved\n * @throws Error if template file is not found or contains invalid JSON\n * \n * @example\n * ```typescript\n * // Input data with template reference\n * const data = {\n * \"@template\": \"defaults/ai-prompt.json\",\n * \"Name\": \"Custom Prompt\",\n * \"Prompt\": \"Override the template prompt\"\n * };\n * \n * // Resolves template and merges with overrides\n * const result = await syncEngine.processTemplates(data, '/path/to/dir');\n * ```\n */\n async processTemplates(data: any, baseDir: string): Promise<any> {\n // Handle arrays\n if (Array.isArray(data)) {\n const processedArray = [];\n for (const item of data) {\n processedArray.push(await this.processTemplates(item, baseDir));\n }\n return processedArray;\n }\n \n // Handle objects\n if (data && typeof data === 'object') {\n // Check for @template reference\n if (typeof data === 'string' && data.startsWith('@template:')) {\n const templatePath = data.substring(10);\n return await this.loadAndProcessTemplate(templatePath, baseDir);\n }\n \n // Process object with possible @template field\n const processed: any = {};\n let templateData: any = {};\n \n // First, check if there's a @template field to process\n if (data['@template']) {\n const templates = Array.isArray(data['@template']) ? data['@template'] : [data['@template']];\n \n // Process templates in order, merging them\n for (const templateRef of templates) {\n const templateContent = await this.loadAndProcessTemplate(templateRef, baseDir);\n templateData = this.deepMerge(templateData, templateContent);\n }\n }\n \n // Process all other fields\n for (const [key, value] of Object.entries(data)) {\n if (key === '@template') continue; // Skip the template field itself\n \n // Process the value recursively\n processed[key] = await this.processTemplates(value, baseDir);\n }\n \n // Merge template data with processed data (processed data takes precedence)\n return this.deepMerge(templateData, processed);\n }\n \n // Return primitive values as-is\n return data;\n }\n \n /**\n * Load and process a template file\n * \n * Loads a JSON template file from the filesystem and recursively processes any\n * nested template references within it. Template paths are resolved relative to\n * the template file's directory, enabling template composition.\n * \n * @param templatePath - Path to the template file (relative or absolute)\n * @param baseDir - Base directory for resolving relative paths\n * @returns Promise resolving to the processed template content\n * @throws Error if template file not found or contains invalid JSON\n * @private\n */\n private async loadAndProcessTemplate(templatePath: string, baseDir: string): Promise<any> {\n const fullPath = path.resolve(baseDir, templatePath);\n \n if (!await fs.pathExists(fullPath)) {\n throw new Error(`Template file not found: ${fullPath}`);\n }\n \n try {\n const templateContent = await fs.readJson(fullPath);\n \n // Recursively process any nested templates\n const templateDir = path.dirname(fullPath);\n return await this.processTemplates(templateContent, templateDir);\n } catch (error) {\n throw new Error(`Failed to load template ${fullPath}: ${error}`);\n }\n }\n \n /**\n * Process file content with {@include} references\n * \n * Recursively processes a file's content to resolve `{@include path}` references.\n * Include references use JSDoc-style syntax and support:\n * - Relative paths resolved from the containing file's directory\n * - Recursive includes (includes within included files)\n * - Circular reference detection to prevent infinite loops\n * - Seamless content substitution maintaining surrounding text\n * \n * @param filePath - Path to the file being processed\n * @param content - The file content to process\n * @param visitedPaths - Set of already visited file paths for circular reference detection\n * @returns Promise resolving to the content with all includes resolved\n * @throws Error if circular reference detected or included file not found\n * \n * @example\n * ```typescript\n * // Content with include reference\n * const content = 'This is a {@include ./shared/header.md} example';\n * \n * // Resolves to:\n * const result = await processFileContentWithIncludes('/path/to/file.md', content);\n * // 'This is a [contents of header.md] example'\n * ```\n */\n private async processFileContentWithIncludes(\n filePath: string, \n content: string, \n visitedPaths: Set<string> = new Set()\n ): Promise<string> {\n // Add current file to visited set\n const absolutePath = path.resolve(filePath);\n if (visitedPaths.has(absolutePath)) {\n throw new Error(`Circular reference detected: ${absolutePath} is already being processed`);\n }\n visitedPaths.add(absolutePath);\n \n // Pattern to match {@include path} references\n // Supports whitespace around the path for flexibility\n const includePattern = /\\{@include\\s+([^\\}]+)\\s*\\}/g;\n \n let processedContent = content;\n let match: RegExpExecArray | null;\n \n // Process all {@include} references\n while ((match = includePattern.exec(content)) !== null) {\n const [fullMatch, includePath] = match;\n const trimmedPath = includePath.trim();\n \n // Resolve the include path relative to the current file's directory\n const currentDir = path.dirname(filePath);\n const resolvedPath = path.resolve(currentDir, trimmedPath);\n \n try {\n // Check if the included file exists\n if (!await fs.pathExists(resolvedPath)) {\n throw new Error(`Included file not found: ${resolvedPath}`);\n }\n \n // Read the included file\n const includedContent = await fs.readFile(resolvedPath, 'utf-8');\n \n // Recursively process the included content for nested includes\n const processedInclude = await this.processFileContentWithIncludes(\n resolvedPath, \n includedContent, \n new Set(visitedPaths) // Pass a copy to allow the same file in different branches\n );\n \n // Replace the {@include} reference with the processed content\n processedContent = processedContent.replace(fullMatch, processedInclude);\n } catch (error) {\n // Enhance error message with context\n throw new Error(`Failed to process {@include ${trimmedPath}} in ${filePath}: ${error}`);\n }\n }\n \n return processedContent;\n }\n \n /**\n * Deep merge two objects with target taking precedence\n * \n * Recursively merges two objects, with values from the target object overriding\n * values from the source object. Arrays and primitive values are not merged but\n * replaced entirely by the target value. Undefined values in target are skipped.\n * \n * @param source - Base object to merge from\n * @param target - Object with values that override source\n * @returns New object with merged values\n * @private\n * \n * @example\n * ```typescript\n * const source = {\n * a: 1,\n * b: { x: 10, y: 20 },\n * c: [1, 2, 3]\n * };\n * const target = {\n * a: 2,\n * b: { y: 30, z: 40 },\n * d: 'new'\n * };\n * const result = deepMerge(source, target);\n * // Result: { a: 2, b: { x: 10, y: 30, z: 40 }, c: [1, 2, 3], d: 'new' }\n * ```\n */\n private deepMerge(source: any, target: any): any {\n if (!source) return target;\n if (!target) return source;\n \n // If target is not an object, it completely overrides source\n if (typeof target !== 'object' || target === null || Array.isArray(target)) {\n return target;\n }\n \n // If source is not an object, target wins\n if (typeof source !== 'object' || source === null || Array.isArray(source)) {\n return target;\n }\n \n // Both are objects, merge them\n const result: any = { ...source };\n \n for (const [key, value] of Object.entries(target)) {\n if (value === undefined) {\n continue; // Skip undefined values\n }\n \n if (typeof value === 'object' && value !== null && !Array.isArray(value) &&\n typeof result[key] === 'object' && result[key] !== null && !Array.isArray(result[key])) {\n // Both are objects, merge recursively\n result[key] = this.deepMerge(result[key], value);\n } else {\n // Otherwise, target value wins\n result[key] = value;\n }\n }\n \n return result;\n }\n \n}"]}
@@ -116,4 +116,17 @@ export declare class ValidationService {
116
116
  * Validate a UserID field value against allowed roles
117
117
  */
118
118
  private validateUserRole;
119
+ /**
120
+ * Validates {@include} references within file content
121
+ *
122
+ * Recursively checks all {@include path} references in file content to ensure:
123
+ * - Referenced files exist
124
+ * - No circular references occur
125
+ * - Include paths are valid
126
+ *
127
+ * @param content - The file content to validate
128
+ * @param filePath - Path of the file being validated
129
+ * @param visitedPaths - Set of already visited paths for circular reference detection
130
+ */
131
+ private validateIncludeReferences;
119
132
  }
@@ -479,6 +479,23 @@ class ValidationService {
479
479
  message: `File reference not found: "${filePath}"`,
480
480
  suggestion: `Create file at: ${resolvedPath}`,
481
481
  });
482
+ return;
483
+ }
484
+ // Read the file and check for {@include} references
485
+ try {
486
+ const content = fs.readFileSync(resolvedPath, 'utf-8');
487
+ await this.validateIncludeReferences(content, resolvedPath, new Set([resolvedPath]));
488
+ }
489
+ catch (error) {
490
+ this.addError({
491
+ type: 'reference',
492
+ severity: 'error',
493
+ entity: entityName,
494
+ field: fieldName,
495
+ file: sourceFile,
496
+ message: `Failed to read file reference: "${filePath}"`,
497
+ details: error instanceof Error ? error.message : String(error),
498
+ });
482
499
  }
483
500
  }
484
501
  /**
@@ -930,6 +947,69 @@ class ValidationService {
930
947
  }
931
948
  }
932
949
  }
950
+ /**
951
+ * Validates {@include} references within file content
952
+ *
953
+ * Recursively checks all {@include path} references in file content to ensure:
954
+ * - Referenced files exist
955
+ * - No circular references occur
956
+ * - Include paths are valid
957
+ *
958
+ * @param content - The file content to validate
959
+ * @param filePath - Path of the file being validated
960
+ * @param visitedPaths - Set of already visited paths for circular reference detection
961
+ */
962
+ async validateIncludeReferences(content, filePath, visitedPaths) {
963
+ // Pattern to match {@include path} references
964
+ const includePattern = /\{@include\s+([^\}]+)\s*\}/g;
965
+ let match;
966
+ while ((match = includePattern.exec(content)) !== null) {
967
+ const [fullMatch, includePath] = match;
968
+ const trimmedPath = includePath.trim();
969
+ // Resolve the include path relative to the current file's directory
970
+ const currentDir = path.dirname(filePath);
971
+ const resolvedPath = path.resolve(currentDir, trimmedPath);
972
+ // Check for circular reference
973
+ if (visitedPaths.has(resolvedPath)) {
974
+ this.addError({
975
+ type: 'reference',
976
+ severity: 'error',
977
+ file: filePath,
978
+ message: `Circular {@include} reference detected: "${trimmedPath}"`,
979
+ details: `Path ${resolvedPath} is already being processed`,
980
+ suggestion: 'Restructure your includes to avoid circular references',
981
+ });
982
+ continue;
983
+ }
984
+ // Check if the included file exists
985
+ if (!fs.existsSync(resolvedPath)) {
986
+ this.addError({
987
+ type: 'reference',
988
+ severity: 'error',
989
+ file: filePath,
990
+ message: `{@include} file not found: "${trimmedPath}"`,
991
+ suggestion: `Create file at: ${resolvedPath}`,
992
+ });
993
+ continue;
994
+ }
995
+ // Recursively validate the included file
996
+ try {
997
+ const includedContent = fs.readFileSync(resolvedPath, 'utf-8');
998
+ const newVisitedPaths = new Set(visitedPaths);
999
+ newVisitedPaths.add(resolvedPath);
1000
+ await this.validateIncludeReferences(includedContent, resolvedPath, newVisitedPaths);
1001
+ }
1002
+ catch (error) {
1003
+ this.addError({
1004
+ type: 'reference',
1005
+ severity: 'error',
1006
+ file: filePath,
1007
+ message: `Failed to read {@include} file: "${trimmedPath}"`,
1008
+ details: error instanceof Error ? error.message : String(error),
1009
+ });
1010
+ }
1011
+ }
1012
+ }
933
1013
  }
934
1014
  exports.ValidationService = ValidationService;
935
1015
  //# sourceMappingURL=ValidationService.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ValidationService.js","sourceRoot":"","sources":["../../src/services/ValidationService.ts"],"names":[],"mappings":"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","sourcesContent":["import { Metadata, RunView } from '@memberjunction/core';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n ValidationResult,\n ValidationError,\n ValidationWarning,\n ValidationOptions,\n FileValidationResult,\n EntityDependency,\n ParsedReference,\n ReferenceType,\n} from '../types/validation';\nimport { RecordData } from '../lib/sync-engine';\nimport { getSystemUser } from '../lib/provider-utils';\n\n// Type aliases for clarity\ntype EntityData = RecordData;\ntype EntitySyncConfig = any;\n\nexport class ValidationService {\n private metadata: Metadata;\n private errors: ValidationError[] = [];\n private warnings: ValidationWarning[] = [];\n private entityDependencies: Map<string, EntityDependency> = new Map();\n private processedEntities: Set<string> = new Set();\n private options: ValidationOptions;\n private userRoleCache: Map<string, string[]> = new Map();\n\n constructor(options: Partial<ValidationOptions> = {}) {\n this.metadata = new Metadata();\n this.options = {\n verbose: false,\n outputFormat: 'human',\n maxNestingDepth: 10,\n checkBestPractices: true,\n ...options,\n };\n }\n\n /**\n * Validates all metadata files in the specified directory\n */\n public async validateDirectory(dir: string): Promise<ValidationResult> {\n this.reset();\n\n const configPath = path.join(dir, '.mj-sync.json');\n if (!fs.existsSync(configPath)) {\n this.addError({\n type: 'entity',\n severity: 'error',\n file: dir,\n message: 'No .mj-sync.json configuration file found in directory',\n });\n return this.getResult();\n }\n\n const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n\n // Load user role configuration and cache if enabled\n if (config.userRoleValidation?.enabled) {\n await this.loadUserRoles();\n }\n\n const directories = await this.getDirectoriesInOrder(dir, config);\n\n let totalFiles = 0;\n let totalEntities = 0;\n const fileResults = new Map<string, FileValidationResult>();\n\n for (const subDir of directories) {\n const subDirPath = path.join(dir, subDir);\n const result = await this.validateEntityDirectory(subDirPath);\n if (result) {\n totalFiles += result.files;\n totalEntities += result.entities;\n for (const [file, fileResult] of result.fileResults) {\n fileResults.set(file, fileResult);\n }\n }\n }\n\n // Validate dependency order\n await this.validateDependencyOrder(directories);\n\n return {\n isValid: this.errors.length === 0,\n errors: this.errors,\n warnings: this.warnings,\n summary: {\n totalFiles,\n totalEntities,\n totalErrors: this.errors.length,\n totalWarnings: this.warnings.length,\n fileResults,\n },\n };\n }\n\n /**\n * Validates a single entity directory\n */\n private async validateEntityDirectory(dir: string): Promise<{ files: number; entities: number; fileResults: Map<string, FileValidationResult> } | null> {\n // Check for .mj-folder.json first (new format)\n let configPath = path.join(dir, '.mj-folder.json');\n let config: any;\n \n if (fs.existsSync(configPath)) {\n config = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n // .mj-folder.json uses entityName field\n if (!config.entityName) {\n this.addError({\n type: 'validation',\n severity: 'error',\n file: configPath,\n message: 'Missing entityName field in .mj-folder.json',\n });\n return null;\n }\n config.entity = config.entityName; // Normalize to entity field\n } else {\n // Fall back to .mj-sync.json (legacy format)\n configPath = path.join(dir, '.mj-sync.json');\n if (!fs.existsSync(configPath)) {\n return null;\n }\n config = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n }\n\n // Validate entity name exists\n if (!config.entity || config.entity.trim() === '') {\n this.addError({\n type: 'validation',\n severity: 'error',\n file: configPath,\n message: 'Entity name is empty or missing',\n });\n return null;\n }\n\n const entityInfo = this.metadata.EntityByName(config.entity);\n\n if (!entityInfo) {\n this.addError({\n type: 'entity',\n severity: 'error',\n file: configPath,\n message: `Entity \"${config.entity}\" not found in metadata`,\n });\n return null;\n }\n\n const files = await this.getMatchingFiles(dir, config.filePattern);\n let totalEntities = 0;\n const fileResults = new Map<string, FileValidationResult>();\n\n for (const file of files) {\n const filePath = path.join(dir, file);\n const result = await this.validateFile(filePath, entityInfo, config);\n totalEntities += result.entityCount;\n fileResults.set(filePath, result);\n }\n\n return { files: files.length, entities: totalEntities, fileResults };\n }\n\n /**\n * Validates a single metadata file\n */\n private async validateFile(filePath: string, entityInfo: any, config: EntitySyncConfig): Promise<FileValidationResult> {\n const fileErrors: ValidationError[] = [];\n let entityCount = 0;\n\n try {\n const content = fs.readFileSync(filePath, 'utf8');\n const data = JSON.parse(content);\n const entities = Array.isArray(data) ? data : [data];\n entityCount = entities.length;\n\n for (const entityData of entities) {\n await this.validateEntityData(entityData, entityInfo, filePath, config);\n }\n } catch (error) {\n fileErrors.push({\n type: 'entity',\n severity: 'error',\n file: filePath,\n message: `Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n\n // Collect errors and warnings for this file\n const currentFileErrors = this.errors.filter((e) => e.file === filePath);\n const currentFileWarnings = this.warnings.filter((w) => w.file === filePath);\n\n return {\n file: filePath,\n entityCount,\n errors: currentFileErrors,\n warnings: currentFileWarnings,\n };\n }\n\n /**\n * Validates a single entity data object\n */\n private async validateEntityData(\n entityData: EntityData,\n entityInfo: any,\n filePath: string,\n config: EntitySyncConfig,\n parentContext?: { entity: string; field: string },\n depth: number = 0,\n ): Promise<void> {\n // Check nesting depth\n if (depth > this.options.maxNestingDepth) {\n this.addWarning({\n type: 'nesting',\n severity: 'warning',\n entity: entityInfo.Name,\n file: filePath,\n message: `Nesting depth ${depth} exceeds recommended maximum of ${this.options.maxNestingDepth}`,\n suggestion: 'Consider flattening the data structure or increasing maxNestingDepth',\n });\n }\n\n // Validate fields\n if (entityData.fields) {\n await this.validateFields(entityData.fields, entityInfo, filePath, parentContext);\n }\n\n // Track dependencies\n this.trackEntityDependencies(entityData, entityInfo.Name, filePath);\n\n // Validate related entities\n if (entityData.relatedEntities) {\n for (const [relatedEntityName, relatedData] of Object.entries(entityData.relatedEntities)) {\n const relatedEntityInfo = this.metadata.EntityByName(relatedEntityName);\n if (!relatedEntityInfo) {\n this.addError({\n type: 'entity',\n severity: 'error',\n entity: entityInfo.Name,\n file: filePath,\n message: `Related entity \"${relatedEntityName}\" not found in metadata`,\n });\n continue;\n }\n\n const relatedEntities = Array.isArray(relatedData) ? relatedData : [relatedData];\n for (const relatedEntity of relatedEntities) {\n await this.validateEntityData(relatedEntity, relatedEntityInfo, filePath, config, { entity: entityInfo.Name, field: relatedEntityName }, depth + 1);\n }\n }\n }\n }\n\n /**\n * Validates entity fields\n */\n private async validateFields(\n fields: Record<string, any>,\n entityInfo: any,\n filePath: string,\n parentContext?: { entity: string; field: string },\n ): Promise<void> {\n const entityFields = entityInfo.Fields;\n const fieldMap = new Map(entityFields.map((f: any) => [f.Name, f]));\n\n for (const [fieldName, fieldValue] of Object.entries(fields)) {\n const fieldInfo = fieldMap.get(fieldName);\n\n if (!fieldInfo) {\n // Check if this might be a virtual property (getter/setter)\n try {\n const entityInstance = await this.metadata.GetEntityObject(entityInfo.Name);\n const hasProperty = fieldName in entityInstance;\n\n if (!hasProperty) {\n this.addError({\n type: 'field',\n severity: 'error',\n entity: entityInfo.Name,\n field: fieldName,\n file: filePath,\n message: `Field \"${fieldName}\" does not exist on entity \"${entityInfo.Name}\"`,\n });\n continue;\n }\n\n // It's a virtual property, validate the value\n await this.validateFieldValue(fieldValue, { Name: fieldName }, entityInfo, filePath, parentContext);\n continue;\n } catch (error) {\n // If we can't create an entity instance, fall back to error\n this.addError({\n type: 'field',\n severity: 'error',\n entity: entityInfo.Name,\n field: fieldName,\n file: filePath,\n message: `Field \"${fieldName}\" does not exist on entity \"${entityInfo.Name}\"`,\n });\n continue;\n }\n }\n\n // Check if field is settable (not system field)\n if ((fieldInfo as any).IsSystemField || fieldName.startsWith('__mj_')) {\n this.addError({\n type: 'field',\n severity: 'error',\n entity: entityInfo.Name,\n field: fieldName,\n file: filePath,\n message: `Field \"${fieldName}\" is a system field and cannot be set`,\n suggestion: 'Remove this field from your metadata file',\n });\n continue;\n }\n\n // Validate field value and references\n await this.validateFieldValue(fieldValue, fieldInfo, entityInfo, filePath, parentContext);\n }\n\n // Check for required fields\n if (this.options.checkBestPractices) {\n for (const field of entityFields) {\n // Skip if field allows null or has a value already\n if (field.AllowsNull || fields[field.Name]) {\n continue;\n }\n\n // Skip if field has a default value\n if (field.DefaultValue !== null && field.DefaultValue !== undefined) {\n continue;\n }\n\n // Skip virtual/computed fields (foreign key reference fields)\n // These are typically named without 'ID' suffix but have a corresponding FK field\n const relatedEntityField = field.RelatedEntity;\n const correspondingFKField = entityFields.find((f: any) => f.Name === field.Name + 'ID' && f.IsForeignKey);\n if (relatedEntityField && correspondingFKField) {\n continue;\n }\n\n // Skip fields that are marked as AutoUpdateOnly or ReadOnly\n if ((field as any).AutoUpdateOnly || (field as any).ReadOnly) {\n continue;\n }\n\n // Skip if this is a parent context and the field can be inherited\n if (parentContext && (field.Name === parentContext.field || field.Name === parentContext.field + 'ID')) {\n continue;\n }\n\n // Special case: Skip TemplateID if TemplateText is provided (virtual property)\n if (field.Name === 'TemplateID' && fields['TemplateText']) {\n continue;\n }\n\n // Skip Template field if TemplateText is provided\n if (field.Name === 'Template' && fields['TemplateText']) {\n continue;\n }\n\n this.addWarning({\n type: 'bestpractice',\n severity: 'warning',\n entity: entityInfo.Name,\n field: field.Name,\n file: filePath,\n message: `Required field \"${field.Name}\" is missing`,\n suggestion: `Add \"${field.Name}\" to the fields object`,\n });\n }\n }\n }\n\n /**\n * Validates field values and references\n */\n private async validateFieldValue(\n value: any,\n fieldInfo: any,\n entityInfo: any,\n filePath: string,\n parentContext?: { entity: string; field: string },\n ): Promise<void> {\n if (typeof value === 'string' && value.startsWith('@')) {\n await this.validateReference(value, fieldInfo, entityInfo, filePath, parentContext);\n }\n\n // Validate UserID fields against allowed roles\n if (fieldInfo.Name === 'UserID' && typeof value === 'string' && value.length > 0) {\n // Get the sync config from the file's directory\n const dir = path.dirname(filePath);\n\n // Walk up to find the root sync config with userRoleValidation\n let currentDir = dir;\n let config = null;\n while (currentDir && currentDir !== path.parse(currentDir).root) {\n const currentConfigPath = path.join(currentDir, '.mj-sync.json');\n if (fs.existsSync(currentConfigPath)) {\n try {\n const currentConfig = JSON.parse(fs.readFileSync(currentConfigPath, 'utf8'));\n if (currentConfig.userRoleValidation) {\n config = currentConfig;\n break;\n }\n } catch {\n // Ignore parse errors\n }\n }\n currentDir = path.dirname(currentDir);\n }\n\n if (config?.userRoleValidation?.enabled) {\n await this.validateUserRole(value, entityInfo.Name, fieldInfo.Name, filePath, config);\n }\n }\n\n // Add other type validation here if needed\n }\n\n /**\n * Validates special references (@file:, @lookup:, etc.)\n */\n private async validateReference(\n reference: string,\n fieldInfo: any,\n entityInfo: any,\n filePath: string,\n parentContext?: { entity: string; field: string },\n ): Promise<void> {\n const parsed = this.parseReference(reference);\n if (!parsed) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityInfo.Name,\n field: fieldInfo.Name,\n file: filePath,\n message: `Invalid reference format: \"${reference}\"`,\n });\n return;\n }\n\n switch (parsed.type) {\n case '@file:':\n await this.validateFileReference(parsed.value, filePath, entityInfo.Name, fieldInfo.Name);\n break;\n case '@lookup:':\n await this.validateLookupReference(parsed, filePath, entityInfo.Name, fieldInfo.Name);\n break;\n case '@template:':\n await this.validateTemplateReference(parsed.value, filePath, entityInfo.Name, fieldInfo.Name);\n break;\n case '@parent:':\n this.validateParentReference(parsed.value, parentContext, filePath, entityInfo.Name, fieldInfo.Name);\n break;\n case '@root:':\n this.validateRootReference(parsed.value, parentContext, filePath, entityInfo.Name, fieldInfo.Name);\n break;\n }\n }\n\n /**\n * Parses a reference string\n */\n private parseReference(reference: string): ParsedReference | null {\n const patterns: [ReferenceType, RegExp][] = [\n ['@file:', /^@file:(.+)$/],\n ['@lookup:', /^@lookup:([^.]+)\\.(.+)$/],\n ['@template:', /^@template:(.+)$/],\n ['@parent:', /^@parent:(.+)$/],\n ['@root:', /^@root:(.+)$/],\n ['@env:', /^@env:(.+)$/],\n ];\n\n for (const [type, pattern] of patterns) {\n const match = reference.match(pattern);\n if (match) {\n if (type === '@lookup:') {\n const [, entity, remaining] = match;\n \n // Check if this has ?create syntax\n const hasCreate = remaining.includes('?create');\n const lookupPart = hasCreate ? remaining.split('?')[0] : remaining;\n \n // Parse all lookup fields (can be multiple with &)\n const lookupPairs = lookupPart.split('&');\n const fields: Array<{field: string, value: string}> = [];\n \n for (const pair of lookupPairs) {\n const fieldMatch = pair.match(/^(.+?)=(.+)$/);\n if (fieldMatch) {\n const [, field, value] = fieldMatch;\n fields.push({ field: field.trim(), value: value.trim() });\n }\n }\n \n // For backward compatibility, use the first field as primary\n const primaryField = fields.length > 0 ? fields[0] : { field: '', value: '' };\n \n // Parse additional fields for creation if ?create is present\n const additionalFields: Record<string, any> = {};\n if (hasCreate && remaining.includes('?create&')) {\n const createPart = remaining.split('?create&')[1];\n const pairs = createPart.split('&');\n for (const pair of pairs) {\n const [key, val] = pair.split('=');\n if (key && val) {\n additionalFields[key] = decodeURIComponent(val);\n }\n }\n }\n\n return { \n type, \n value: primaryField.value, \n entity, \n field: primaryField.field,\n fields, // Include all fields for validation\n createIfMissing: hasCreate, \n additionalFields \n };\n }\n return { type, value: match[1] };\n }\n }\n\n return null;\n }\n\n /**\n * Validates @file: references\n */\n private async validateFileReference(filePath: string, sourceFile: string, entityName: string, fieldName: string): Promise<void> {\n const dir = path.dirname(sourceFile);\n const resolvedPath = path.resolve(dir, filePath);\n\n if (!fs.existsSync(resolvedPath)) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `File reference not found: \"${filePath}\"`,\n suggestion: `Create file at: ${resolvedPath}`,\n });\n }\n }\n\n /**\n * Validates @lookup: references\n */\n private async validateLookupReference(parsed: ParsedReference, sourceFile: string, entityName: string, fieldName: string): Promise<void> {\n const lookupEntity = this.metadata.EntityByName(parsed.entity!);\n\n if (!lookupEntity) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `Lookup entity \"${parsed.entity}\" not found`,\n suggestion: 'Check entity name spelling and case',\n });\n return;\n }\n\n // For multi-field lookups, validate all fields\n if (parsed.fields && parsed.fields.length > 0) {\n for (const {field} of parsed.fields) {\n const lookupField = lookupEntity.Fields.find((f: any) => f.Name === field);\n if (!lookupField) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `Lookup field \"${field}\" not found on entity \"${parsed.entity}\"`,\n suggestion: `Available fields: ${lookupEntity.Fields.map((f: any) => f.Name).join(', ')}`,\n });\n }\n }\n } else if (parsed.field) {\n // Fallback for single field lookup (backward compatibility)\n const lookupField = lookupEntity.Fields.find((f: any) => f.Name === parsed.field);\n if (!lookupField) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `Lookup field \"${parsed.field}\" not found on entity \"${parsed.entity}\"`,\n suggestion: `Available fields: ${lookupEntity.Fields.map((f: any) => f.Name).join(', ')}`,\n });\n }\n }\n\n // Track dependency\n this.addEntityDependency(entityName, parsed.entity!);\n }\n\n /**\n * Validates @template: references\n */\n private async validateTemplateReference(templatePath: string, sourceFile: string, entityName: string, fieldName: string): Promise<void> {\n const dir = path.dirname(sourceFile);\n const resolvedPath = path.resolve(dir, templatePath);\n\n if (!fs.existsSync(resolvedPath)) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `Template file not found: \"${templatePath}\"`,\n suggestion: `Create template at: ${resolvedPath}`,\n });\n return;\n }\n\n // Validate template is valid JSON\n try {\n JSON.parse(fs.readFileSync(resolvedPath, 'utf8'));\n } catch (error) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `Template file is not valid JSON: \"${templatePath}\"`,\n details: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Validates @parent: references\n */\n private validateParentReference(\n _fieldName: string,\n parentContext: { entity: string; field: string } | undefined,\n sourceFile: string,\n entityName: string,\n currentFieldName: string,\n ): void {\n if (!parentContext) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: currentFieldName,\n file: sourceFile,\n message: `@parent: reference used but no parent context exists`,\n suggestion: '@parent: can only be used in nested/related entities',\n });\n }\n }\n\n /**\n * Validates @root: references\n */\n private validateRootReference(\n _fieldName: string,\n parentContext: { entity: string; field: string } | undefined,\n sourceFile: string,\n entityName: string,\n currentFieldName: string,\n ): void {\n if (!parentContext) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: currentFieldName,\n file: sourceFile,\n message: `@root: reference used but no root context exists`,\n suggestion: '@root: can only be used in nested/related entities',\n });\n }\n }\n\n /**\n * Track entity dependencies\n */\n private trackEntityDependencies(entityData: EntityData, entityName: string, filePath: string): void {\n if (!this.entityDependencies.has(entityName)) {\n this.entityDependencies.set(entityName, {\n entityName,\n dependsOn: new Set(),\n file: filePath,\n });\n }\n\n // Track dependencies from lookups in fields\n if (entityData.fields) {\n for (const value of Object.values(entityData.fields)) {\n if (typeof value === 'string' && value.startsWith('@lookup:')) {\n const parsed = this.parseReference(value);\n if (parsed?.entity) {\n this.addEntityDependency(entityName, parsed.entity);\n }\n }\n }\n }\n }\n\n /**\n * Add an entity dependency\n */\n private addEntityDependency(from: string, to: string): void {\n // Don't add self-references as dependencies (e.g., ParentID in hierarchical structures)\n if (from === to) {\n return;\n }\n \n if (!this.entityDependencies.has(from)) {\n this.entityDependencies.set(from, {\n entityName: from,\n dependsOn: new Set(),\n file: '',\n });\n }\n this.entityDependencies.get(from)!.dependsOn.add(to);\n }\n\n /**\n * Validates dependency order\n */\n private async validateDependencyOrder(directoryOrder: string[]): Promise<void> {\n // Build a map of entity to directory\n const entityToDirectory = new Map<string, string>();\n\n for (const dir of directoryOrder) {\n // This is simplified - in reality we'd need to read the .mj-sync.json\n // to get the actual entity name\n entityToDirectory.set(dir, dir);\n }\n\n // Check for circular dependencies\n const visited = new Set<string>();\n const recursionStack = new Set<string>();\n\n for (const [entity] of this.entityDependencies) {\n if (!visited.has(entity)) {\n this.checkCircularDependency(entity, visited, recursionStack);\n }\n }\n\n // Check if current order satisfies dependencies\n const orderViolations = this.checkDependencyOrder(directoryOrder);\n if (orderViolations.length > 0) {\n // Suggest a corrected order\n const suggestedOrder = this.topologicalSort();\n\n for (const violation of orderViolations) {\n this.addError({\n type: 'dependency',\n severity: 'error',\n entity: violation.entity,\n file: violation.file,\n message: `Entity '${violation.entity}' depends on '${violation.dependency}' but is processed before it`,\n suggestion: `Reorder directories to: [${suggestedOrder.join(', ')}]`,\n });\n }\n }\n }\n\n /**\n * Check for circular dependencies\n */\n private checkCircularDependency(entity: string, visited: Set<string>, recursionStack: Set<string>, path: string[] = []): boolean {\n visited.add(entity);\n recursionStack.add(entity);\n path.push(entity);\n\n const deps = this.entityDependencies.get(entity);\n if (deps) {\n for (const dep of deps.dependsOn) {\n if (!visited.has(dep)) {\n if (this.checkCircularDependency(dep, visited, recursionStack, [...path])) {\n return true;\n }\n } else if (recursionStack.has(dep)) {\n // Found circular dependency\n const cycle = [...path, dep];\n const cycleStart = cycle.indexOf(dep);\n const cyclePath = cycle.slice(cycleStart).join(' → ');\n\n this.addError({\n type: 'circular',\n severity: 'error',\n entity: entity,\n file: deps.file,\n message: `Circular dependency detected: ${cyclePath}`,\n suggestion: 'Restructure your entities to avoid circular references',\n });\n return true;\n }\n }\n }\n\n recursionStack.delete(entity);\n return false;\n }\n\n /**\n * Get directories in order based on config\n */\n private async getDirectoriesInOrder(rootDir: string, config: any): Promise<string[]> {\n const allDirs = fs\n .readdirSync(rootDir)\n .filter((f) => fs.statSync(path.join(rootDir, f)).isDirectory())\n .filter((d) => !d.startsWith('.'));\n\n if (config.directoryOrder && Array.isArray(config.directoryOrder)) {\n const ordered = config.directoryOrder.filter((d: string) => allDirs.includes(d));\n const remaining = allDirs.filter((d) => !ordered.includes(d)).sort();\n return [...ordered, ...remaining];\n }\n\n return allDirs.sort();\n }\n\n /**\n * Get files matching pattern\n */\n private async getMatchingFiles(dir: string, pattern: string): Promise<string[]> {\n const files = fs.readdirSync(dir).filter((f) => fs.statSync(path.join(dir, f)).isFile());\n\n // Simple glob pattern matching\n if (pattern === '*.json') {\n return files.filter((f) => f.endsWith('.json') && !f.startsWith('.mj-'));\n } else if (pattern === '.*.json') {\n return files.filter((f) => f.startsWith('.') && f.endsWith('.json') && !f.startsWith('.mj-'));\n }\n\n return files;\n }\n\n /**\n * Add an error\n */\n private addError(error: ValidationError): void {\n this.errors.push(error);\n }\n\n /**\n * Add a warning\n */\n private addWarning(warning: ValidationWarning): void {\n this.warnings.push(warning);\n }\n\n /**\n * Check if current directory order satisfies dependencies\n */\n private checkDependencyOrder(directoryOrder: string[]): Array<{ entity: string; dependency: string; file: string }> {\n const violations: Array<{ entity: string; dependency: string; file: string }> = [];\n const processedEntities = new Set<string>();\n\n for (const dir of directoryOrder) {\n // In real implementation, we'd read .mj-sync.json to get entity name\n const entityName = dir; // Simplified for now\n\n const deps = this.entityDependencies.get(entityName);\n if (deps) {\n for (const dep of deps.dependsOn) {\n if (!processedEntities.has(dep) && directoryOrder.includes(dep)) {\n violations.push({\n entity: entityName,\n dependency: dep,\n file: deps.file,\n });\n }\n }\n }\n\n processedEntities.add(entityName);\n }\n\n return violations;\n }\n\n /**\n * Perform topological sort on entity dependencies\n */\n private topologicalSort(): string[] {\n const result: string[] = [];\n const visited = new Set<string>();\n const tempStack = new Set<string>();\n\n const visit = (entity: string): boolean => {\n if (tempStack.has(entity)) {\n // Circular dependency, already handled by checkCircularDependency\n return false;\n }\n\n if (visited.has(entity)) {\n return true;\n }\n\n tempStack.add(entity);\n\n const deps = this.entityDependencies.get(entity);\n if (deps) {\n for (const dep of deps.dependsOn) {\n if (!visit(dep)) {\n return false;\n }\n }\n }\n\n tempStack.delete(entity);\n visited.add(entity);\n result.push(entity);\n\n return true;\n };\n\n // Visit all entities\n for (const entity of this.entityDependencies.keys()) {\n if (!visited.has(entity)) {\n visit(entity);\n }\n }\n\n return result;\n }\n\n /**\n * Reset validation state\n */\n private reset(): void {\n this.errors = [];\n this.warnings = [];\n this.entityDependencies.clear();\n this.processedEntities.clear();\n this.userRoleCache.clear();\n }\n\n /**\n * Get validation result\n */\n private getResult(): ValidationResult {\n return {\n isValid: this.errors.length === 0,\n errors: this.errors,\n warnings: this.warnings,\n summary: {\n totalFiles: 0,\n totalEntities: 0,\n totalErrors: this.errors.length,\n totalWarnings: this.warnings.length,\n fileResults: new Map(),\n },\n };\n }\n\n /**\n * Load user roles from the database into cache\n */\n private async loadUserRoles(): Promise<void> {\n try {\n const rv = new RunView();\n const systemUser = getSystemUser();\n\n // Load all user roles with role names\n const result = await rv.RunView(\n {\n EntityName: 'User Roles',\n ExtraFilter: '',\n OrderBy: 'UserID',\n MaxRows: 10000,\n },\n systemUser,\n );\n\n if (!result.Success) {\n this.addWarning({\n type: 'validation',\n severity: 'warning',\n file: 'system',\n message: 'Failed to load user roles for validation',\n details: result.ErrorMessage,\n });\n return;\n }\n\n // Group roles by UserID\n for (const userRole of result.Results || []) {\n const userId = userRole.UserID;\n const roleName = userRole.Role;\n\n if (!this.userRoleCache.has(userId)) {\n this.userRoleCache.set(userId, []);\n }\n this.userRoleCache.get(userId)!.push(roleName);\n }\n\n if (this.options.verbose) {\n console.log(`Loaded roles for ${this.userRoleCache.size} users`);\n }\n } catch (error) {\n this.addWarning({\n type: 'validation',\n severity: 'warning',\n file: 'system',\n message: 'Error loading user roles for validation',\n details: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Validate a UserID field value against allowed roles\n */\n private async validateUserRole(userId: string, entityName: string, fieldName: string, filePath: string, config: any): Promise<void> {\n // Skip if user role validation is not enabled\n if (!config.userRoleValidation?.enabled) {\n return;\n }\n\n const userRoles = this.userRoleCache.get(userId);\n const allowedRoles = config.userRoleValidation.allowedRoles || [];\n const allowUsersWithoutRoles = config.userRoleValidation.allowUsersWithoutRoles || false;\n\n if (!userRoles || userRoles.length === 0) {\n if (!allowUsersWithoutRoles) {\n this.addError({\n type: 'validation',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: filePath,\n message: `UserID '${userId}' does not have any assigned roles`,\n suggestion:\n allowedRoles.length > 0\n ? `User must have one of these roles: ${allowedRoles.join(', ')}`\n : 'Assign appropriate roles to this user or set allowUsersWithoutRoles: true',\n });\n }\n return;\n }\n\n // Check if user has at least one allowed role\n if (allowedRoles.length > 0) {\n const hasAllowedRole = userRoles.some((role) => allowedRoles.includes(role));\n if (!hasAllowedRole) {\n this.addError({\n type: 'validation',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: filePath,\n message: `UserID '${userId}' has roles [${userRoles.join(', ')}] but none are in allowed list`,\n suggestion: `Allowed roles: ${allowedRoles.join(', ')}`,\n });\n }\n }\n }\n}\n"]}
1
+ {"version":3,"file":"ValidationService.js","sourceRoot":"","sources":["../../src/services/ValidationService.ts"],"names":[],"mappings":"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","sourcesContent":["import { Metadata, RunView } from '@memberjunction/core';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n ValidationResult,\n ValidationError,\n ValidationWarning,\n ValidationOptions,\n FileValidationResult,\n EntityDependency,\n ParsedReference,\n ReferenceType,\n} from '../types/validation';\nimport { RecordData } from '../lib/sync-engine';\nimport { getSystemUser } from '../lib/provider-utils';\n\n// Type aliases for clarity\ntype EntityData = RecordData;\ntype EntitySyncConfig = any;\n\nexport class ValidationService {\n private metadata: Metadata;\n private errors: ValidationError[] = [];\n private warnings: ValidationWarning[] = [];\n private entityDependencies: Map<string, EntityDependency> = new Map();\n private processedEntities: Set<string> = new Set();\n private options: ValidationOptions;\n private userRoleCache: Map<string, string[]> = new Map();\n\n constructor(options: Partial<ValidationOptions> = {}) {\n this.metadata = new Metadata();\n this.options = {\n verbose: false,\n outputFormat: 'human',\n maxNestingDepth: 10,\n checkBestPractices: true,\n ...options,\n };\n }\n\n /**\n * Validates all metadata files in the specified directory\n */\n public async validateDirectory(dir: string): Promise<ValidationResult> {\n this.reset();\n\n const configPath = path.join(dir, '.mj-sync.json');\n if (!fs.existsSync(configPath)) {\n this.addError({\n type: 'entity',\n severity: 'error',\n file: dir,\n message: 'No .mj-sync.json configuration file found in directory',\n });\n return this.getResult();\n }\n\n const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n\n // Load user role configuration and cache if enabled\n if (config.userRoleValidation?.enabled) {\n await this.loadUserRoles();\n }\n\n const directories = await this.getDirectoriesInOrder(dir, config);\n\n let totalFiles = 0;\n let totalEntities = 0;\n const fileResults = new Map<string, FileValidationResult>();\n\n for (const subDir of directories) {\n const subDirPath = path.join(dir, subDir);\n const result = await this.validateEntityDirectory(subDirPath);\n if (result) {\n totalFiles += result.files;\n totalEntities += result.entities;\n for (const [file, fileResult] of result.fileResults) {\n fileResults.set(file, fileResult);\n }\n }\n }\n\n // Validate dependency order\n await this.validateDependencyOrder(directories);\n\n return {\n isValid: this.errors.length === 0,\n errors: this.errors,\n warnings: this.warnings,\n summary: {\n totalFiles,\n totalEntities,\n totalErrors: this.errors.length,\n totalWarnings: this.warnings.length,\n fileResults,\n },\n };\n }\n\n /**\n * Validates a single entity directory\n */\n private async validateEntityDirectory(dir: string): Promise<{ files: number; entities: number; fileResults: Map<string, FileValidationResult> } | null> {\n // Check for .mj-folder.json first (new format)\n let configPath = path.join(dir, '.mj-folder.json');\n let config: any;\n \n if (fs.existsSync(configPath)) {\n config = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n // .mj-folder.json uses entityName field\n if (!config.entityName) {\n this.addError({\n type: 'validation',\n severity: 'error',\n file: configPath,\n message: 'Missing entityName field in .mj-folder.json',\n });\n return null;\n }\n config.entity = config.entityName; // Normalize to entity field\n } else {\n // Fall back to .mj-sync.json (legacy format)\n configPath = path.join(dir, '.mj-sync.json');\n if (!fs.existsSync(configPath)) {\n return null;\n }\n config = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n }\n\n // Validate entity name exists\n if (!config.entity || config.entity.trim() === '') {\n this.addError({\n type: 'validation',\n severity: 'error',\n file: configPath,\n message: 'Entity name is empty or missing',\n });\n return null;\n }\n\n const entityInfo = this.metadata.EntityByName(config.entity);\n\n if (!entityInfo) {\n this.addError({\n type: 'entity',\n severity: 'error',\n file: configPath,\n message: `Entity \"${config.entity}\" not found in metadata`,\n });\n return null;\n }\n\n const files = await this.getMatchingFiles(dir, config.filePattern);\n let totalEntities = 0;\n const fileResults = new Map<string, FileValidationResult>();\n\n for (const file of files) {\n const filePath = path.join(dir, file);\n const result = await this.validateFile(filePath, entityInfo, config);\n totalEntities += result.entityCount;\n fileResults.set(filePath, result);\n }\n\n return { files: files.length, entities: totalEntities, fileResults };\n }\n\n /**\n * Validates a single metadata file\n */\n private async validateFile(filePath: string, entityInfo: any, config: EntitySyncConfig): Promise<FileValidationResult> {\n const fileErrors: ValidationError[] = [];\n let entityCount = 0;\n\n try {\n const content = fs.readFileSync(filePath, 'utf8');\n const data = JSON.parse(content);\n const entities = Array.isArray(data) ? data : [data];\n entityCount = entities.length;\n\n for (const entityData of entities) {\n await this.validateEntityData(entityData, entityInfo, filePath, config);\n }\n } catch (error) {\n fileErrors.push({\n type: 'entity',\n severity: 'error',\n file: filePath,\n message: `Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n\n // Collect errors and warnings for this file\n const currentFileErrors = this.errors.filter((e) => e.file === filePath);\n const currentFileWarnings = this.warnings.filter((w) => w.file === filePath);\n\n return {\n file: filePath,\n entityCount,\n errors: currentFileErrors,\n warnings: currentFileWarnings,\n };\n }\n\n /**\n * Validates a single entity data object\n */\n private async validateEntityData(\n entityData: EntityData,\n entityInfo: any,\n filePath: string,\n config: EntitySyncConfig,\n parentContext?: { entity: string; field: string },\n depth: number = 0,\n ): Promise<void> {\n // Check nesting depth\n if (depth > this.options.maxNestingDepth) {\n this.addWarning({\n type: 'nesting',\n severity: 'warning',\n entity: entityInfo.Name,\n file: filePath,\n message: `Nesting depth ${depth} exceeds recommended maximum of ${this.options.maxNestingDepth}`,\n suggestion: 'Consider flattening the data structure or increasing maxNestingDepth',\n });\n }\n\n // Validate fields\n if (entityData.fields) {\n await this.validateFields(entityData.fields, entityInfo, filePath, parentContext);\n }\n\n // Track dependencies\n this.trackEntityDependencies(entityData, entityInfo.Name, filePath);\n\n // Validate related entities\n if (entityData.relatedEntities) {\n for (const [relatedEntityName, relatedData] of Object.entries(entityData.relatedEntities)) {\n const relatedEntityInfo = this.metadata.EntityByName(relatedEntityName);\n if (!relatedEntityInfo) {\n this.addError({\n type: 'entity',\n severity: 'error',\n entity: entityInfo.Name,\n file: filePath,\n message: `Related entity \"${relatedEntityName}\" not found in metadata`,\n });\n continue;\n }\n\n const relatedEntities = Array.isArray(relatedData) ? relatedData : [relatedData];\n for (const relatedEntity of relatedEntities) {\n await this.validateEntityData(relatedEntity, relatedEntityInfo, filePath, config, { entity: entityInfo.Name, field: relatedEntityName }, depth + 1);\n }\n }\n }\n }\n\n /**\n * Validates entity fields\n */\n private async validateFields(\n fields: Record<string, any>,\n entityInfo: any,\n filePath: string,\n parentContext?: { entity: string; field: string },\n ): Promise<void> {\n const entityFields = entityInfo.Fields;\n const fieldMap = new Map(entityFields.map((f: any) => [f.Name, f]));\n\n for (const [fieldName, fieldValue] of Object.entries(fields)) {\n const fieldInfo = fieldMap.get(fieldName);\n\n if (!fieldInfo) {\n // Check if this might be a virtual property (getter/setter)\n try {\n const entityInstance = await this.metadata.GetEntityObject(entityInfo.Name);\n const hasProperty = fieldName in entityInstance;\n\n if (!hasProperty) {\n this.addError({\n type: 'field',\n severity: 'error',\n entity: entityInfo.Name,\n field: fieldName,\n file: filePath,\n message: `Field \"${fieldName}\" does not exist on entity \"${entityInfo.Name}\"`,\n });\n continue;\n }\n\n // It's a virtual property, validate the value\n await this.validateFieldValue(fieldValue, { Name: fieldName }, entityInfo, filePath, parentContext);\n continue;\n } catch (error) {\n // If we can't create an entity instance, fall back to error\n this.addError({\n type: 'field',\n severity: 'error',\n entity: entityInfo.Name,\n field: fieldName,\n file: filePath,\n message: `Field \"${fieldName}\" does not exist on entity \"${entityInfo.Name}\"`,\n });\n continue;\n }\n }\n\n // Check if field is settable (not system field)\n if ((fieldInfo as any).IsSystemField || fieldName.startsWith('__mj_')) {\n this.addError({\n type: 'field',\n severity: 'error',\n entity: entityInfo.Name,\n field: fieldName,\n file: filePath,\n message: `Field \"${fieldName}\" is a system field and cannot be set`,\n suggestion: 'Remove this field from your metadata file',\n });\n continue;\n }\n\n // Validate field value and references\n await this.validateFieldValue(fieldValue, fieldInfo, entityInfo, filePath, parentContext);\n }\n\n // Check for required fields\n if (this.options.checkBestPractices) {\n for (const field of entityFields) {\n // Skip if field allows null or has a value already\n if (field.AllowsNull || fields[field.Name]) {\n continue;\n }\n\n // Skip if field has a default value\n if (field.DefaultValue !== null && field.DefaultValue !== undefined) {\n continue;\n }\n\n // Skip virtual/computed fields (foreign key reference fields)\n // These are typically named without 'ID' suffix but have a corresponding FK field\n const relatedEntityField = field.RelatedEntity;\n const correspondingFKField = entityFields.find((f: any) => f.Name === field.Name + 'ID' && f.IsForeignKey);\n if (relatedEntityField && correspondingFKField) {\n continue;\n }\n\n // Skip fields that are marked as AutoUpdateOnly or ReadOnly\n if ((field as any).AutoUpdateOnly || (field as any).ReadOnly) {\n continue;\n }\n\n // Skip if this is a parent context and the field can be inherited\n if (parentContext && (field.Name === parentContext.field || field.Name === parentContext.field + 'ID')) {\n continue;\n }\n\n // Special case: Skip TemplateID if TemplateText is provided (virtual property)\n if (field.Name === 'TemplateID' && fields['TemplateText']) {\n continue;\n }\n\n // Skip Template field if TemplateText is provided\n if (field.Name === 'Template' && fields['TemplateText']) {\n continue;\n }\n\n this.addWarning({\n type: 'bestpractice',\n severity: 'warning',\n entity: entityInfo.Name,\n field: field.Name,\n file: filePath,\n message: `Required field \"${field.Name}\" is missing`,\n suggestion: `Add \"${field.Name}\" to the fields object`,\n });\n }\n }\n }\n\n /**\n * Validates field values and references\n */\n private async validateFieldValue(\n value: any,\n fieldInfo: any,\n entityInfo: any,\n filePath: string,\n parentContext?: { entity: string; field: string },\n ): Promise<void> {\n if (typeof value === 'string' && value.startsWith('@')) {\n await this.validateReference(value, fieldInfo, entityInfo, filePath, parentContext);\n }\n\n // Validate UserID fields against allowed roles\n if (fieldInfo.Name === 'UserID' && typeof value === 'string' && value.length > 0) {\n // Get the sync config from the file's directory\n const dir = path.dirname(filePath);\n\n // Walk up to find the root sync config with userRoleValidation\n let currentDir = dir;\n let config = null;\n while (currentDir && currentDir !== path.parse(currentDir).root) {\n const currentConfigPath = path.join(currentDir, '.mj-sync.json');\n if (fs.existsSync(currentConfigPath)) {\n try {\n const currentConfig = JSON.parse(fs.readFileSync(currentConfigPath, 'utf8'));\n if (currentConfig.userRoleValidation) {\n config = currentConfig;\n break;\n }\n } catch {\n // Ignore parse errors\n }\n }\n currentDir = path.dirname(currentDir);\n }\n\n if (config?.userRoleValidation?.enabled) {\n await this.validateUserRole(value, entityInfo.Name, fieldInfo.Name, filePath, config);\n }\n }\n\n // Add other type validation here if needed\n }\n\n /**\n * Validates special references (@file:, @lookup:, etc.)\n */\n private async validateReference(\n reference: string,\n fieldInfo: any,\n entityInfo: any,\n filePath: string,\n parentContext?: { entity: string; field: string },\n ): Promise<void> {\n const parsed = this.parseReference(reference);\n if (!parsed) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityInfo.Name,\n field: fieldInfo.Name,\n file: filePath,\n message: `Invalid reference format: \"${reference}\"`,\n });\n return;\n }\n\n switch (parsed.type) {\n case '@file:':\n await this.validateFileReference(parsed.value, filePath, entityInfo.Name, fieldInfo.Name);\n break;\n case '@lookup:':\n await this.validateLookupReference(parsed, filePath, entityInfo.Name, fieldInfo.Name);\n break;\n case '@template:':\n await this.validateTemplateReference(parsed.value, filePath, entityInfo.Name, fieldInfo.Name);\n break;\n case '@parent:':\n this.validateParentReference(parsed.value, parentContext, filePath, entityInfo.Name, fieldInfo.Name);\n break;\n case '@root:':\n this.validateRootReference(parsed.value, parentContext, filePath, entityInfo.Name, fieldInfo.Name);\n break;\n }\n }\n\n /**\n * Parses a reference string\n */\n private parseReference(reference: string): ParsedReference | null {\n const patterns: [ReferenceType, RegExp][] = [\n ['@file:', /^@file:(.+)$/],\n ['@lookup:', /^@lookup:([^.]+)\\.(.+)$/],\n ['@template:', /^@template:(.+)$/],\n ['@parent:', /^@parent:(.+)$/],\n ['@root:', /^@root:(.+)$/],\n ['@env:', /^@env:(.+)$/],\n ];\n\n for (const [type, pattern] of patterns) {\n const match = reference.match(pattern);\n if (match) {\n if (type === '@lookup:') {\n const [, entity, remaining] = match;\n \n // Check if this has ?create syntax\n const hasCreate = remaining.includes('?create');\n const lookupPart = hasCreate ? remaining.split('?')[0] : remaining;\n \n // Parse all lookup fields (can be multiple with &)\n const lookupPairs = lookupPart.split('&');\n const fields: Array<{field: string, value: string}> = [];\n \n for (const pair of lookupPairs) {\n const fieldMatch = pair.match(/^(.+?)=(.+)$/);\n if (fieldMatch) {\n const [, field, value] = fieldMatch;\n fields.push({ field: field.trim(), value: value.trim() });\n }\n }\n \n // For backward compatibility, use the first field as primary\n const primaryField = fields.length > 0 ? fields[0] : { field: '', value: '' };\n \n // Parse additional fields for creation if ?create is present\n const additionalFields: Record<string, any> = {};\n if (hasCreate && remaining.includes('?create&')) {\n const createPart = remaining.split('?create&')[1];\n const pairs = createPart.split('&');\n for (const pair of pairs) {\n const [key, val] = pair.split('=');\n if (key && val) {\n additionalFields[key] = decodeURIComponent(val);\n }\n }\n }\n\n return { \n type, \n value: primaryField.value, \n entity, \n field: primaryField.field,\n fields, // Include all fields for validation\n createIfMissing: hasCreate, \n additionalFields \n };\n }\n return { type, value: match[1] };\n }\n }\n\n return null;\n }\n\n /**\n * Validates @file: references\n */\n private async validateFileReference(filePath: string, sourceFile: string, entityName: string, fieldName: string): Promise<void> {\n const dir = path.dirname(sourceFile);\n const resolvedPath = path.resolve(dir, filePath);\n\n if (!fs.existsSync(resolvedPath)) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `File reference not found: \"${filePath}\"`,\n suggestion: `Create file at: ${resolvedPath}`,\n });\n return;\n }\n\n // Read the file and check for {@include} references\n try {\n const content = fs.readFileSync(resolvedPath, 'utf-8');\n await this.validateIncludeReferences(content, resolvedPath, new Set([resolvedPath]));\n } catch (error) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `Failed to read file reference: \"${filePath}\"`,\n details: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Validates @lookup: references\n */\n private async validateLookupReference(parsed: ParsedReference, sourceFile: string, entityName: string, fieldName: string): Promise<void> {\n const lookupEntity = this.metadata.EntityByName(parsed.entity!);\n\n if (!lookupEntity) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `Lookup entity \"${parsed.entity}\" not found`,\n suggestion: 'Check entity name spelling and case',\n });\n return;\n }\n\n // For multi-field lookups, validate all fields\n if (parsed.fields && parsed.fields.length > 0) {\n for (const {field} of parsed.fields) {\n const lookupField = lookupEntity.Fields.find((f: any) => f.Name === field);\n if (!lookupField) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `Lookup field \"${field}\" not found on entity \"${parsed.entity}\"`,\n suggestion: `Available fields: ${lookupEntity.Fields.map((f: any) => f.Name).join(', ')}`,\n });\n }\n }\n } else if (parsed.field) {\n // Fallback for single field lookup (backward compatibility)\n const lookupField = lookupEntity.Fields.find((f: any) => f.Name === parsed.field);\n if (!lookupField) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `Lookup field \"${parsed.field}\" not found on entity \"${parsed.entity}\"`,\n suggestion: `Available fields: ${lookupEntity.Fields.map((f: any) => f.Name).join(', ')}`,\n });\n }\n }\n\n // Track dependency\n this.addEntityDependency(entityName, parsed.entity!);\n }\n\n /**\n * Validates @template: references\n */\n private async validateTemplateReference(templatePath: string, sourceFile: string, entityName: string, fieldName: string): Promise<void> {\n const dir = path.dirname(sourceFile);\n const resolvedPath = path.resolve(dir, templatePath);\n\n if (!fs.existsSync(resolvedPath)) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `Template file not found: \"${templatePath}\"`,\n suggestion: `Create template at: ${resolvedPath}`,\n });\n return;\n }\n\n // Validate template is valid JSON\n try {\n JSON.parse(fs.readFileSync(resolvedPath, 'utf8'));\n } catch (error) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: sourceFile,\n message: `Template file is not valid JSON: \"${templatePath}\"`,\n details: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Validates @parent: references\n */\n private validateParentReference(\n _fieldName: string,\n parentContext: { entity: string; field: string } | undefined,\n sourceFile: string,\n entityName: string,\n currentFieldName: string,\n ): void {\n if (!parentContext) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: currentFieldName,\n file: sourceFile,\n message: `@parent: reference used but no parent context exists`,\n suggestion: '@parent: can only be used in nested/related entities',\n });\n }\n }\n\n /**\n * Validates @root: references\n */\n private validateRootReference(\n _fieldName: string,\n parentContext: { entity: string; field: string } | undefined,\n sourceFile: string,\n entityName: string,\n currentFieldName: string,\n ): void {\n if (!parentContext) {\n this.addError({\n type: 'reference',\n severity: 'error',\n entity: entityName,\n field: currentFieldName,\n file: sourceFile,\n message: `@root: reference used but no root context exists`,\n suggestion: '@root: can only be used in nested/related entities',\n });\n }\n }\n\n /**\n * Track entity dependencies\n */\n private trackEntityDependencies(entityData: EntityData, entityName: string, filePath: string): void {\n if (!this.entityDependencies.has(entityName)) {\n this.entityDependencies.set(entityName, {\n entityName,\n dependsOn: new Set(),\n file: filePath,\n });\n }\n\n // Track dependencies from lookups in fields\n if (entityData.fields) {\n for (const value of Object.values(entityData.fields)) {\n if (typeof value === 'string' && value.startsWith('@lookup:')) {\n const parsed = this.parseReference(value);\n if (parsed?.entity) {\n this.addEntityDependency(entityName, parsed.entity);\n }\n }\n }\n }\n }\n\n /**\n * Add an entity dependency\n */\n private addEntityDependency(from: string, to: string): void {\n // Don't add self-references as dependencies (e.g., ParentID in hierarchical structures)\n if (from === to) {\n return;\n }\n \n if (!this.entityDependencies.has(from)) {\n this.entityDependencies.set(from, {\n entityName: from,\n dependsOn: new Set(),\n file: '',\n });\n }\n this.entityDependencies.get(from)!.dependsOn.add(to);\n }\n\n /**\n * Validates dependency order\n */\n private async validateDependencyOrder(directoryOrder: string[]): Promise<void> {\n // Build a map of entity to directory\n const entityToDirectory = new Map<string, string>();\n\n for (const dir of directoryOrder) {\n // This is simplified - in reality we'd need to read the .mj-sync.json\n // to get the actual entity name\n entityToDirectory.set(dir, dir);\n }\n\n // Check for circular dependencies\n const visited = new Set<string>();\n const recursionStack = new Set<string>();\n\n for (const [entity] of this.entityDependencies) {\n if (!visited.has(entity)) {\n this.checkCircularDependency(entity, visited, recursionStack);\n }\n }\n\n // Check if current order satisfies dependencies\n const orderViolations = this.checkDependencyOrder(directoryOrder);\n if (orderViolations.length > 0) {\n // Suggest a corrected order\n const suggestedOrder = this.topologicalSort();\n\n for (const violation of orderViolations) {\n this.addError({\n type: 'dependency',\n severity: 'error',\n entity: violation.entity,\n file: violation.file,\n message: `Entity '${violation.entity}' depends on '${violation.dependency}' but is processed before it`,\n suggestion: `Reorder directories to: [${suggestedOrder.join(', ')}]`,\n });\n }\n }\n }\n\n /**\n * Check for circular dependencies\n */\n private checkCircularDependency(entity: string, visited: Set<string>, recursionStack: Set<string>, path: string[] = []): boolean {\n visited.add(entity);\n recursionStack.add(entity);\n path.push(entity);\n\n const deps = this.entityDependencies.get(entity);\n if (deps) {\n for (const dep of deps.dependsOn) {\n if (!visited.has(dep)) {\n if (this.checkCircularDependency(dep, visited, recursionStack, [...path])) {\n return true;\n }\n } else if (recursionStack.has(dep)) {\n // Found circular dependency\n const cycle = [...path, dep];\n const cycleStart = cycle.indexOf(dep);\n const cyclePath = cycle.slice(cycleStart).join(' → ');\n\n this.addError({\n type: 'circular',\n severity: 'error',\n entity: entity,\n file: deps.file,\n message: `Circular dependency detected: ${cyclePath}`,\n suggestion: 'Restructure your entities to avoid circular references',\n });\n return true;\n }\n }\n }\n\n recursionStack.delete(entity);\n return false;\n }\n\n /**\n * Get directories in order based on config\n */\n private async getDirectoriesInOrder(rootDir: string, config: any): Promise<string[]> {\n const allDirs = fs\n .readdirSync(rootDir)\n .filter((f) => fs.statSync(path.join(rootDir, f)).isDirectory())\n .filter((d) => !d.startsWith('.'));\n\n if (config.directoryOrder && Array.isArray(config.directoryOrder)) {\n const ordered = config.directoryOrder.filter((d: string) => allDirs.includes(d));\n const remaining = allDirs.filter((d) => !ordered.includes(d)).sort();\n return [...ordered, ...remaining];\n }\n\n return allDirs.sort();\n }\n\n /**\n * Get files matching pattern\n */\n private async getMatchingFiles(dir: string, pattern: string): Promise<string[]> {\n const files = fs.readdirSync(dir).filter((f) => fs.statSync(path.join(dir, f)).isFile());\n\n // Simple glob pattern matching\n if (pattern === '*.json') {\n return files.filter((f) => f.endsWith('.json') && !f.startsWith('.mj-'));\n } else if (pattern === '.*.json') {\n return files.filter((f) => f.startsWith('.') && f.endsWith('.json') && !f.startsWith('.mj-'));\n }\n\n return files;\n }\n\n /**\n * Add an error\n */\n private addError(error: ValidationError): void {\n this.errors.push(error);\n }\n\n /**\n * Add a warning\n */\n private addWarning(warning: ValidationWarning): void {\n this.warnings.push(warning);\n }\n\n /**\n * Check if current directory order satisfies dependencies\n */\n private checkDependencyOrder(directoryOrder: string[]): Array<{ entity: string; dependency: string; file: string }> {\n const violations: Array<{ entity: string; dependency: string; file: string }> = [];\n const processedEntities = new Set<string>();\n\n for (const dir of directoryOrder) {\n // In real implementation, we'd read .mj-sync.json to get entity name\n const entityName = dir; // Simplified for now\n\n const deps = this.entityDependencies.get(entityName);\n if (deps) {\n for (const dep of deps.dependsOn) {\n if (!processedEntities.has(dep) && directoryOrder.includes(dep)) {\n violations.push({\n entity: entityName,\n dependency: dep,\n file: deps.file,\n });\n }\n }\n }\n\n processedEntities.add(entityName);\n }\n\n return violations;\n }\n\n /**\n * Perform topological sort on entity dependencies\n */\n private topologicalSort(): string[] {\n const result: string[] = [];\n const visited = new Set<string>();\n const tempStack = new Set<string>();\n\n const visit = (entity: string): boolean => {\n if (tempStack.has(entity)) {\n // Circular dependency, already handled by checkCircularDependency\n return false;\n }\n\n if (visited.has(entity)) {\n return true;\n }\n\n tempStack.add(entity);\n\n const deps = this.entityDependencies.get(entity);\n if (deps) {\n for (const dep of deps.dependsOn) {\n if (!visit(dep)) {\n return false;\n }\n }\n }\n\n tempStack.delete(entity);\n visited.add(entity);\n result.push(entity);\n\n return true;\n };\n\n // Visit all entities\n for (const entity of this.entityDependencies.keys()) {\n if (!visited.has(entity)) {\n visit(entity);\n }\n }\n\n return result;\n }\n\n /**\n * Reset validation state\n */\n private reset(): void {\n this.errors = [];\n this.warnings = [];\n this.entityDependencies.clear();\n this.processedEntities.clear();\n this.userRoleCache.clear();\n }\n\n /**\n * Get validation result\n */\n private getResult(): ValidationResult {\n return {\n isValid: this.errors.length === 0,\n errors: this.errors,\n warnings: this.warnings,\n summary: {\n totalFiles: 0,\n totalEntities: 0,\n totalErrors: this.errors.length,\n totalWarnings: this.warnings.length,\n fileResults: new Map(),\n },\n };\n }\n\n /**\n * Load user roles from the database into cache\n */\n private async loadUserRoles(): Promise<void> {\n try {\n const rv = new RunView();\n const systemUser = getSystemUser();\n\n // Load all user roles with role names\n const result = await rv.RunView(\n {\n EntityName: 'User Roles',\n ExtraFilter: '',\n OrderBy: 'UserID',\n MaxRows: 10000,\n },\n systemUser,\n );\n\n if (!result.Success) {\n this.addWarning({\n type: 'validation',\n severity: 'warning',\n file: 'system',\n message: 'Failed to load user roles for validation',\n details: result.ErrorMessage,\n });\n return;\n }\n\n // Group roles by UserID\n for (const userRole of result.Results || []) {\n const userId = userRole.UserID;\n const roleName = userRole.Role;\n\n if (!this.userRoleCache.has(userId)) {\n this.userRoleCache.set(userId, []);\n }\n this.userRoleCache.get(userId)!.push(roleName);\n }\n\n if (this.options.verbose) {\n console.log(`Loaded roles for ${this.userRoleCache.size} users`);\n }\n } catch (error) {\n this.addWarning({\n type: 'validation',\n severity: 'warning',\n file: 'system',\n message: 'Error loading user roles for validation',\n details: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Validate a UserID field value against allowed roles\n */\n private async validateUserRole(userId: string, entityName: string, fieldName: string, filePath: string, config: any): Promise<void> {\n // Skip if user role validation is not enabled\n if (!config.userRoleValidation?.enabled) {\n return;\n }\n\n const userRoles = this.userRoleCache.get(userId);\n const allowedRoles = config.userRoleValidation.allowedRoles || [];\n const allowUsersWithoutRoles = config.userRoleValidation.allowUsersWithoutRoles || false;\n\n if (!userRoles || userRoles.length === 0) {\n if (!allowUsersWithoutRoles) {\n this.addError({\n type: 'validation',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: filePath,\n message: `UserID '${userId}' does not have any assigned roles`,\n suggestion:\n allowedRoles.length > 0\n ? `User must have one of these roles: ${allowedRoles.join(', ')}`\n : 'Assign appropriate roles to this user or set allowUsersWithoutRoles: true',\n });\n }\n return;\n }\n\n // Check if user has at least one allowed role\n if (allowedRoles.length > 0) {\n const hasAllowedRole = userRoles.some((role) => allowedRoles.includes(role));\n if (!hasAllowedRole) {\n this.addError({\n type: 'validation',\n severity: 'error',\n entity: entityName,\n field: fieldName,\n file: filePath,\n message: `UserID '${userId}' has roles [${userRoles.join(', ')}] but none are in allowed list`,\n suggestion: `Allowed roles: ${allowedRoles.join(', ')}`,\n });\n }\n }\n }\n\n /**\n * Validates {@include} references within file content\n * \n * Recursively checks all {@include path} references in file content to ensure:\n * - Referenced files exist\n * - No circular references occur\n * - Include paths are valid\n * \n * @param content - The file content to validate\n * @param filePath - Path of the file being validated\n * @param visitedPaths - Set of already visited paths for circular reference detection\n */\n private async validateIncludeReferences(content: string, filePath: string, visitedPaths: Set<string>): Promise<void> {\n // Pattern to match {@include path} references\n const includePattern = /\\{@include\\s+([^\\}]+)\\s*\\}/g;\n let match: RegExpExecArray | null;\n \n while ((match = includePattern.exec(content)) !== null) {\n const [fullMatch, includePath] = match;\n const trimmedPath = includePath.trim();\n \n // Resolve the include path relative to the current file's directory\n const currentDir = path.dirname(filePath);\n const resolvedPath = path.resolve(currentDir, trimmedPath);\n \n // Check for circular reference\n if (visitedPaths.has(resolvedPath)) {\n this.addError({\n type: 'reference',\n severity: 'error',\n file: filePath,\n message: `Circular {@include} reference detected: \"${trimmedPath}\"`,\n details: `Path ${resolvedPath} is already being processed`,\n suggestion: 'Restructure your includes to avoid circular references',\n });\n continue;\n }\n \n // Check if the included file exists\n if (!fs.existsSync(resolvedPath)) {\n this.addError({\n type: 'reference',\n severity: 'error',\n file: filePath,\n message: `{@include} file not found: \"${trimmedPath}\"`,\n suggestion: `Create file at: ${resolvedPath}`,\n });\n continue;\n }\n \n // Recursively validate the included file\n try {\n const includedContent = fs.readFileSync(resolvedPath, 'utf-8');\n const newVisitedPaths = new Set(visitedPaths);\n newVisitedPaths.add(resolvedPath);\n await this.validateIncludeReferences(includedContent, resolvedPath, newVisitedPaths);\n } catch (error) {\n this.addError({\n type: 'reference',\n severity: 'error',\n file: filePath,\n message: `Failed to read {@include} file: \"${trimmedPath}\"`,\n details: error instanceof Error ? error.message : String(error),\n });\n }\n }\n }\n}\n"]}
@@ -372,5 +372,5 @@
372
372
  ]
373
373
  }
374
374
  },
375
- "version": "2.53.0"
375
+ "version": "2.54.0"
376
376
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/metadata-sync",
3
- "version": "2.53.0",
3
+ "version": "2.54.0",
4
4
  "description": "MemberJunction metadata synchronization CLI tool",
5
5
  "keywords": [
6
6
  "oclif",
@@ -51,12 +51,12 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "@inquirer/prompts": "^5.0.1",
54
- "@memberjunction/core": "2.53.0",
55
- "@memberjunction/core-entities": "2.53.0",
56
- "@memberjunction/core-entities-server": "2.53.0",
57
- "@memberjunction/global": "2.53.0",
58
- "@memberjunction/sqlserver-dataprovider": "2.53.0",
59
- "@memberjunction/graphql-dataprovider": "2.53.0",
54
+ "@memberjunction/core": "2.54.0",
55
+ "@memberjunction/core-entities": "2.54.0",
56
+ "@memberjunction/core-entities-server": "2.54.0",
57
+ "@memberjunction/global": "2.54.0",
58
+ "@memberjunction/sqlserver-dataprovider": "2.54.0",
59
+ "@memberjunction/graphql-dataprovider": "2.54.0",
60
60
  "@oclif/core": "^3",
61
61
  "@oclif/plugin-help": "^6",
62
62
  "@oclif/plugin-version": "^2.0.17",