api-v1/core/utils/SchemaFileLoader.js

74 lines
2.1 KiB
JavaScript

import fs from 'fs';
import path from 'path';
export default class SchemaFileLoader {
/**
* Load a schema JSON file and resolve all nested json_dtype references
*
* @param {string} filePath - Absolute or relative path to schema file
* @param {Set<string>} visited - Internal circular reference protection
* @returns {object} Fully resolved schema JSON
*/
static load(filePath, visited = new Set()) {
const absolutePath = path.resolve(filePath);
if (visited.has(absolutePath)) {
throw new Error(`Circular schema reference detected: ${absolutePath}`);
}
visited.add(absolutePath);
if (!fs.existsSync(absolutePath)) {
throw new Error(`Schema file not found: ${absolutePath}`);
}
const raw = fs.readFileSync(absolutePath, 'utf-8');
const schema = JSON.parse(raw);
const baseDir = path.dirname(absolutePath);
return this._resolveSchema(schema, baseDir, visited);
}
/**
* Recursively resolve json_dtype references
*/
static _resolveSchema(schema, baseDir, visited) {
if (typeof schema !== 'object' || schema === null) return schema;
for (const field in schema) {
const rule = schema[field];
if (!rule || typeof rule !== 'object') continue;
// Resolve nested JSON object schema
if (
rule.type === 'JSONObject' ||
rule.type === 'JSONArray'
) {
if (typeof rule.json_dtype === 'string') {
const nestedPath = path.join(baseDir, rule.json_dtype);
rule.json_dtype = this.load(nestedPath, visited);
} else if (typeof rule.json_dtype === 'object') {
rule.json_dtype = this._resolveSchema(
rule.json_dtype,
baseDir,
visited
);
}
}
// Resolve array of JSON objects
if (
rule.type === 'Array' &&
rule.array_dtype === 'JSONObject'
) {
if (typeof rule.json_dtype === 'string') {
const nestedPath = path.join(baseDir, rule.json_dtype);
rule.json_dtype = this.load(nestedPath, visited);
}
}
}
return schema;
}
}