UNPKG

nuvira

Version:

Nuvira Database. New Database format (Readable & Easy to use), (Inbuilt Schema & constraints & rules & relations).

192 lines 7.69 kB
export class NuviraSchema { lines; position; parsedSchema; errors; allowedTypes; schemaName; constructor({ lines, position = 0, allowedTypes = [] }) { this.lines = lines; this.position = position; this.parsedSchema = {}; this.errors = []; this.allowedTypes = allowedTypes; this.schemaName = 'unnamed-schema'; } parseSchema() { this.processSchemaName(this.lines); this.schemaName = this.processSchemaName(this.lines) ?? "unnamed-schema"; while (this.position < this.lines.length) { const line = this.lines[this.position].trim(); if (line.startsWith('!#')) { this.position++; continue; } if (line === "@end") { break; } this.processLine(line); this.position++; } return { schemaName: this.schemaName, parsedSchema: this.parsedSchema, errors: this.errors, lines: this.lines, position: this.position }; } processSchemaName(lines) { const schemaLine = lines.find(line => line.startsWith("@schema")); if (!schemaLine) { this.errors.push({ line: this.position + 1, message: `Missing '@schema' declaration.`, }); return null; } const match = schemaLine.match(/^@schema:\s*([a-zA-Z0-9_-]+)$/); if (match) { this.schemaName = match[1]; } return this.schemaName; } /** * Processes each line of the schema and updates the parsedSchema and errors accordingly. * * @param {string} line - The line of schema to process. */ processLine(line) { if (!line || line.startsWith('!#')) { return; } const arrowIndex = line.indexOf("->"); if (arrowIndex !== -1) { const key = line.substring(0, arrowIndex).trim(); const value = line.substring(arrowIndex + 2).trim(); const types = this.parseSubTypes(value); if ((types.includes("Object") || types.includes("ObjectArray") || types.includes("Object[]")) && types.some((type) => type !== "Object" && type !== "ObjectArray" && type !== "Object[]")) { this.errors.push({ line: this.position + 1, message: `Invalid combination: ${types.join(", ")} for key: ${key}. Only 'Object' or 'ObjectArray' can be used with each other, but no other types.`, }); return; } if (value.startsWith("Object {")) { this.parsedSchema[key] = { type: ["Object"], properties: this.parseInlineNestedObject(), }; } else if (value.startsWith("ObjectArray {") || value.startsWith("Object[] {")) { this.parsedSchema[key] = { type: ["ObjectArray"], items: this.parseInlineNestedArray(), }; } else { const invalidTypes = types.filter((type) => !this.allowedTypes.includes(type)); if (invalidTypes.length > 0) { this.errors.push({ line: this.position + 1, message: `Invalid types: ${invalidTypes.join(", ")} for key: ${key}`, }); return; } this.parsedSchema[key] = { type: types }; } } } /** * Parses a nested object schema defined inline within the schema. * * @returns {Record<string, any>} The parsed nested object schema. */ parseInlineNestedObject() { const nestedObject = {}; this.position++; while (this.position < this.lines.length) { const line = this.lines[this.position].trim(); if (line.startsWith('!#')) { this.position++; continue; } if (line === "}") break; if (line.includes("->")) { const arrowIndex = line.indexOf("->"); const nestedKey = line.substring(0, arrowIndex).trim(); const nestedValue = line.substring(arrowIndex + 2).trim(); const types = this.parseSubTypes(nestedValue); // Define object type mappings const objectTypes = new Map([ ["Object {", { key: "properties", method: this.parseInlineNestedObject.bind(this) }], ["ObjectArray {", { key: "items", method: this.parseInlineNestedArray.bind(this) }], ["Object[] {", { key: "items", method: this.parseInlineNestedArray.bind(this) }] ]); const objectType = [...objectTypes.keys()].find(type => nestedValue.startsWith(type)); if (objectType) { nestedObject[nestedKey] = { type: [objectType.replace(" {", "")], [objectTypes.get(objectType).key]: objectTypes.get(objectType).method(), }; } else { nestedObject[nestedKey] = { type: types }; } } this.position++; } return nestedObject; } /** * Parses a nested array schema defined inline within the schema. * * @returns {Record<string, any>} The parsed nested array schema. */ parseInlineNestedArray() { const arraySchema = {}; this.position++; while (this.position < this.lines.length) { const line = this.lines[this.position].trim(); if (line.startsWith('!#')) { this.position++; continue; } if (line === "}") break; if (line.includes("->")) { const arrowIndex = line.indexOf("->"); const nestedKey = line.substring(0, arrowIndex).trim(); const nestedValue = line.substring(arrowIndex + 2).trim(); const types = this.parseSubTypes(nestedValue); // Define object type mappings const objectTypes = new Map([ ["Object {", { key: "properties", method: this.parseInlineNestedObject.bind(this) }], ["ObjectArray {", { key: "items", method: this.parseInlineNestedArray.bind(this) }], ["Object[] {", { key: "items", method: this.parseInlineNestedArray.bind(this) }] ]); const objectType = [...objectTypes.keys()].find(type => nestedValue.startsWith(type)); if (objectType) { arraySchema[nestedKey] = { type: [objectType.replace(" {", "")], [objectTypes.get(objectType).key]: objectTypes.get(objectType).method(), }; } else { arraySchema[nestedKey] = { type: types }; } } this.position++; } return arraySchema; } /** * Parses the types defined in the schema for a given value. * * @param {string} value - The value to extract types from. * @returns {string[]} An array of types. */ parseSubTypes(value) { return value .split("|") .map(v => v.trim().replace(/[\s\{\}]+$/, "")) .filter(Boolean); } } //# sourceMappingURL=parseSchema.js.map