UNPKG

@tripsnek/tmf

Version:

TypeScript Modeling Framework - A TypeScript port of the Eclipse Modeling Framework (EMF)

749 lines 98 kB
import { TUtils } from '../tutils.js'; import { EClassImpl } from '../metamodel/impl/eclass-impl.js'; import { EReferenceImpl } from '../metamodel/impl/ereference-impl.js'; /** * Utilities for converting between EObjects and JSON. Usage: * * (1) TJson.makeJson(EObject) - converts an EObject to JSON. * (2) TJson.makeEObject(json) - deserializes EObject encoded with (1). * (3) TJson.makeJsonArray(EObject[]) - converts an array of EObjects to a JSON Array. * (4) TJson.makeEObjectArray(json) - converts a JSON Array to an array of EObjects. * * You may also configure which EClasses are eligible for conversion with * 'addPackages(EPackage[])' and 'setPackages(EPackage[])'. * */ export class TJson { //the name of the special JSON field that indicates each object's type static JSON_FIELD_TYPESCRIPT_TYPE = '@type'; //These will be automatically added by the PackageInitializer when a Package is "touched" static packages = []; static setPackages(packages) { this.packages = packages; } //automatically used by package initializers to add JSON serialization support when they are touched static addPackages(packages) { for (const p of packages) { if (!this.packages.includes(p)) this.packages.push(p); } } //the currently registered EPackages static getPackages() { return TJson.packages; } // Simple check - warn if no packages registered static warnIfNotInitialized() { if (this.packages.length === 0) { console.warn('TJson: No packages registered. Call the package initializer using ' + '<MyRootPackage>PackageInitializer.registerAll() before using TJson'); } } /** * Converts a TMF EObject to JSON. * * @param obj */ static makeJson(obj) { this.warnIfNotInitialized(); const context = new SerializationContext(obj); return this.eObjectToJsonAux(obj, new Map(), false, context); } /** * Converts an object in JSON Object into a TMF EObject. * Creates proxy objects for unresolved non-containment references. * * @param json * @return */ static makeEObject(jsonObj) { this.warnIfNotInitialized(); const serializedReferences = new Array(); //build containment heirarchy const eobj = this.jsonToEObject(jsonObj, serializedReferences); if (!eobj) return undefined; // Create deserialization context const context = new DeserializationContext(eobj); //deserialize references, collecting unresolved ones const unresolvedRefs = new Array(); serializedReferences.forEach((ref) => { if (!ref.deserialize(context)) { unresolvedRefs.push(ref); } }); // Create proxies for unresolved references unresolvedRefs.forEach((ref) => { this.createAndSetProxy(ref, context); }); return eobj; } /** * Creates a proxy object for an unresolved reference and sets it on the source object. * * @param ref The unresolved serialized reference * @param context The deserialization context */ static createAndSetProxy(ref, context) { // Handle SerializedReferenceWithObject specially let fromObj; if (ref instanceof SerializedReferenceWithObject) { fromObj = ref.fromObj; if (!fromObj || !ref.toId) return; } else { if (!ref.fromId || !ref.toId) return; fromObj = context.resolveId(ref.fromId); if (!fromObj) return; } // Path-based IDs that couldn't be resolved are internal inconsistencies if (ref.toId.startsWith('@path:')) { console.warn(`Cannot create proxy for unresolved path-based reference: ${ref.toId}`); return; } const feature = fromObj.eClass().getEStructuralFeature(ref.refName); if (!feature || !(feature instanceof EReferenceImpl)) return; // Check if proxy already exists for this target let proxy = context.resolveId(ref.toId); if (!proxy) { proxy = this.createProxy(ref.toId, feature); if (proxy) { // Add proxy to the index so future references to it can be resolved context.getIndex().set(ref.toId, proxy); } } if (proxy) { // Set the reference if (feature.isMany()) { fromObj.eGet(feature).add(proxy); } else { fromObj.eSet(feature, proxy); } } } /** * Creates a proxy EObject for an unresolved reference. * * @param fullId The full ID of the target object (format: "ClassName_actualId") * @param reference The reference feature to determine the target EClass * @returns A proxy EObject or undefined if creation failed */ static createProxy(fullId, reference) { // Path-based IDs cannot be proxied (they're internal references that should have been resolved) if (fullId.startsWith('@path:')) { console.warn(`Cannot create proxy for path-based ID: ${fullId}`); return undefined; } // Parse the fullId to extract class name and actual ID const underscoreIndex = fullId.indexOf('_'); if (underscoreIndex === -1) { console.warn(`Invalid fullId format for proxy creation: ${fullId}`); return undefined; } const className = fullId.substring(0, underscoreIndex); const actualId = fullId.substring(underscoreIndex + 1); // Get the target EClass from the reference type const targetEClass = reference.getEType(); if (!targetEClass) { console.warn(`No target EClass found for reference: ${reference.getName()}`); return undefined; } // Verify the class name matches (safety check) if (targetEClass.getName() !== className) { console.warn(`Class name mismatch for proxy: expected ${className}, got ${targetEClass.getName()}`); // Continue anyway - the reference type is authoritative } // Find the appropriate EPackage and factory for (const pkg of this.packages) { const classifiers = pkg.getEClassifiers(); for (const classifier of classifiers) { if (classifier === targetEClass) { try { // Create the proxy object const proxy = pkg.getEFactoryInstance().create(targetEClass); // Set the ID attribute if it exists const idAttribute = targetEClass.getEIDAttribute(); if (idAttribute) { try { // Parse the ID value to the correct type using TUtils const parsedId = TUtils.parseAttrValFromString(idAttribute, actualId); proxy.eSet(idAttribute, parsedId); } catch (error) { console.warn(`Failed to parse ID value for proxy: ${actualId}`, error); } } // Mark as proxy proxy.eSetProxy(true); // console.debug(`Created proxy object for ${fullId}`); return proxy; } catch (error) { console.error(`Failed to create proxy for ${fullId}:`, error); return undefined; } } } } console.warn(`No EPackage found containing EClass ${targetEClass.getName()} for proxy creation`); return undefined; } /** * Converts a TMF EObject array to JSON array. * * @param obj */ static makeJsonArray(objs) { this.warnIfNotInitialized(); const jsonArray = []; if (objs) { objs.forEach((element) => { jsonArray.push(this.makeJson(element)); }); } return jsonArray; } /** * Converts an object in JSON Array into am array of TMF EObjects. * * @param json * @return */ static makeEObjectArray(jsonArray) { this.warnIfNotInitialized(); const eobjArray = []; jsonArray.forEach((element) => { const eobj = this.makeEObject(element); if (eobj) eobjArray.push(eobj); }); return eobjArray; } static jsonToEObject(jsonObj, serializedRefs) { if (jsonObj == null) { throw new Error('ERROR: null value for JSON Object. Cannot convert to EObject.'); } //get the type indicator and instantiate the TMF Object const objectType = jsonObj[this.JSON_FIELD_TYPESCRIPT_TYPE]; if (objectType == null) { console.error('ERROR: No value for ' + this.JSON_FIELD_TYPESCRIPT_TYPE + ' was specified for the JSON object: ' + jsonObj); return undefined; } let eClass; let eObj; for (const pkg of this.packages) { eClass = this.eClassByNameCaseInsensitive(objectType, pkg); if (eClass) { eObj = pkg.getEFactoryInstance().create(eClass); break; } } if (eClass && eObj) { //handle all primitive attributes this.setPrimitiveValuesOnJson(jsonObj, eObj); //handle all references for (const ref of eObj.eClass().getEAllReferences()) { this.deserializeReferencedObjects(jsonObj, eObj, ref, serializedRefs); } } return eObj; } static deserializeReferencedObjects(jsonObj, dObj, ref, serializedRefs) { const jsonFieldName = this.getJsonFieldName(ref); //multi-valued references if (ref.isMany()) { this.deserializeManyValuedReference(jsonObj, jsonFieldName, ref, dObj, serializedRefs); } //single-valued references else { this.deserializeSingleValuedReference(jsonObj, jsonFieldName, ref, dObj, serializedRefs); } } static deserializeSingleValuedReference(jsonObj, jsonFieldName, ref, tObj, serializedRefs) { const referencedObj = jsonObj[jsonFieldName]; if (referencedObj) { if (ref.isContainment()) { const containeTJsonObj = referencedObj; if (!containeTJsonObj[this.JSON_FIELD_TYPESCRIPT_TYPE]) { containeTJsonObj[this.JSON_FIELD_TYPESCRIPT_TYPE] = ref.getEType().getName(); } const referencedEmfObj = this.jsonToEObject(containeTJsonObj, serializedRefs); tObj.eSet(ref, referencedEmfObj); } else { // Store the object itself, not its ID - we'll resolve IDs later serializedRefs.push(new SerializedReferenceWithObject(tObj, referencedObj, ref.getName())); } } } static deserializeManyValuedReference(jsonObj, jsonFieldName, ref, tObj, serializedRefs) { const jsonArray = jsonObj[jsonFieldName]; if (jsonArray) { jsonArray.forEach((containedTJsonObj, index) => { if (ref.isContainment()) { if (!containedTJsonObj[this.JSON_FIELD_TYPESCRIPT_TYPE]) { containedTJsonObj[this.JSON_FIELD_TYPESCRIPT_TYPE] = ref .getEType() .getName(); } const containedDObj = this.jsonToEObject(containedTJsonObj, serializedRefs); tObj.eGet(ref).add(containedDObj); } else { // Store the object itself, not its ID - we'll resolve IDs later serializedRefs.push(new SerializedReferenceWithObject(tObj, containedTJsonObj, ref.getName())); } }); } } static eObjectToJsonAux(obj, serializedSoFar, attributesOnly, context) { //make sure there is really an object to convert if (obj == null) { return null; } const jsonObj = {}; //Generate IDs for all Entities in the heirarchy which do not have them if (!TUtils.getOrCreateIdForObject(obj)) TUtils.genIdIfNotExists(obj); //add a type indicator for everything (the class name) jsonObj[this.JSON_FIELD_TYPESCRIPT_TYPE] = obj.eClass().getName(); //handle all primitive attributes this.attributesToJson(obj, jsonObj); //handle all references if (!attributesOnly) { this.referencesToJson(obj, serializedSoFar, jsonObj, context); } return jsonObj; } static referencesToJson(obj, serializedSoFar, jsonObj, context) { for (const ref of obj.eClass().getEAllReferences()) { if (!ref.isVolatile() && !ref.isTransient()) { //multi-valued references if (ref.isMany()) { this.manyValuedReferenceToJson(obj, ref, serializedSoFar, jsonObj, context); } //single-valued references else { this.singleValuedRefToJson(obj, ref, serializedSoFar, jsonObj, context); } } } } static manyValuedReferenceToJson(obj, ref, serializedSoFar, jsonObj, context) { const jsonFieldName = this.getJsonFieldName(ref); const jsonArray = []; for (const referencedObj of obj.eGet(ref)) { if (referencedObj != null) { if (ref.isContainment()) { const referenceTJsonObj = this.eObjectToJsonAux(referencedObj, serializedSoFar, !ref.isContainment(), context); if (referenceTJsonObj != null) jsonArray.push(referenceTJsonObj); } else { const fromId = context.getStableId(obj); const toId = context.getStableId(referencedObj); const serializedRef = new SerializedReference(fromId, toId, jsonFieldName).serialize(); jsonArray.push(serializedRef); } } } jsonObj[jsonFieldName] = jsonArray; } static singleValuedRefToJson(obj, ref, serializedSoFar, jsonObj, context) { const jsonFieldName = this.getJsonFieldName(ref); const referencedObj = obj.eGet(ref); if (referencedObj != null) { let referenceTJsonObj = null; //if the object is 'contained', we generate it's full representation if (ref.isContainment()) { referenceTJsonObj = this.eObjectToJsonAux(referencedObj, serializedSoFar, !ref.isContainment(), context); } //otherwise, we generate a serialized pointer to the referenced object else { const fromId = context.getStableId(obj); const toId = context.getStableId(referencedObj); referenceTJsonObj = new SerializedReference(fromId, toId, jsonFieldName).serialize(); } if (referenceTJsonObj != null) jsonObj[jsonFieldName] = referenceTJsonObj; } } static attributesToJson(obj, jsonObj) { for (const attr of obj.eClass().getEAllAttributes()) { if (!attr.isVolatile() && !attr.isTransient()) { const jsonFieldName = this.getJsonFieldName(attr); const origVal = obj.eGet(attr); const convertedVal = this.primitiveValueToJson(attr, origVal); jsonObj[jsonFieldName] = convertedVal; } } } /** * Converts a primitive value (or a Date) for use inside JSON. * * @param val * @return */ static primitiveValueToJson(attr, val) { //serialize many-valued eattributes if (attr.isMany()) { const toRet = []; for (const v of val) { toRet.push(v instanceof Date ? v.toJSON() : v); } return toRet; } if (val instanceof Date) { return val.toJSON(); } return val; } static getJsonFieldName(feature) { return feature.getName(); } static eClassByNameCaseInsensitive(objectType, pkg) { let dClass = pkg.getEClassifier(objectType); if (dClass) { //case insensitive checking of names for (const eclass of pkg.getEClassifiers()) { if (eclass instanceof EClassImpl && eclass.getName().toLowerCase() === objectType.toLowerCase()) { dClass = eclass; } } } return dClass; } /** * Sets all primitive (EAttribute) values on the eobject, given a * JSONObject with the same fields. * * @param propsObj * @param eObj */ static setPrimitiveValuesOnJson(propsObj, eObj) { for (const attr of eObj.eClass().getEAllAttributes()) { const jsonFieldName = this.getJsonFieldName(attr); const jsonVal = propsObj[jsonFieldName]; if (jsonVal || jsonVal === 0) { if (attr.isMany()) { const array = jsonVal; const coll = eObj.eGet(attr); for (const o of array) { coll.add(TUtils.parseAttrValFromString(attr, o)); } } else { const tVal = TUtils.parseAttrValFromString(attr, jsonVal); if (tVal || tVal === 0) { eObj.eSet(attr, tVal); } else { console.warn('JSON parse failed for ' + eObj.eClass().getName() + '.' + attr.getName() + ' with value ' + jsonVal.toString()); } } } } } } export class SerializedReference { fromId; toId; refName; constructor(from, to, ref) { this.fromId = from; this.toId = to; this.refName = ref; } static create(fromDId, toDId, fromRef) { return new SerializedReference(fromDId, toDId, fromRef); } /** * Swizzles the object to JSON. */ serialize() { return this.toId; } /** * Restores the swizzled reference. * * @param context The deserialization context * @returns true if the reference was successfully resolved, false if target object not found */ deserialize(context) { const fromObj = context.resolveId(this.fromId); const toObj = context.resolveId(this.toId); if (fromObj && toObj) { const feature = fromObj.eClass().getEStructuralFeature(this.refName); //enforce the reference if (fromObj && toObj && feature) { if (feature.isMany()) fromObj.eGet(feature).add(toObj); else fromObj.eSet(feature, toObj); return true; } } return false; } } /** * Context object for managing state during serialization */ class SerializationContext { tempIdCounter = 0; objectToTempId = new Map(); root; constructor(root) { this.root = root; } /** * Gets or creates a stable identifier for an object. * Uses the object's ID if available, otherwise creates a path-based identifier. */ getStableId(obj) { // First try to get the actual ID const actualId = TUtils.getOrCreateIdForObject(obj); if (actualId) { return actualId; } // Check if we already created a temp ID for this object const existingTempId = this.objectToTempId.get(obj); if (existingTempId) { return existingTempId; } // Create and cache a path-based identifier const pathId = this.createPathBasedId(obj); this.objectToTempId.set(obj, pathId); return pathId; } /** * Creates a path-based identifier for an object based on its containment path. * Format: "@path:ClassName:/feature1[index]/feature2[index]/..." */ createPathBasedId(obj) { if (obj === this.root) { return `@path:${obj.eClass().getName()}:@root`; } const path = []; let current = obj; while (current && current !== this.root) { const container = current.eContainer(); if (!container) break; // Find which containment feature holds this object for (const ref of container.eClass().getEAllReferences()) { if (ref.isContainment()) { const value = container.eGet(ref); if (ref.isMany()) { const list = value; const index = list.indexOf(current); if (index >= 0) { path.unshift(`${ref.getName()}[${index}]`); break; } } else if (value === current) { path.unshift(ref.getName()); break; } } } current = container; } return `@path:${obj.eClass().getName()}:/${path.join('/')}`; } } /** * Context object for managing state during deserialization */ class DeserializationContext { pathToObject = new Map(); root; idsToObjs = new Map(); constructor(root) { this.root = root; this.buildIndex(); } /** * Builds an index of all contained objects using both real IDs and path-based IDs */ buildIndex() { // Add root const rootId = this.getStableId(this.root); this.idsToObjs.set(rootId, this.root); // Add all contained objects this.root.eAllContents().forEach((elem) => { const id = this.getStableId(elem); this.idsToObjs.set(id, elem); }); } /** * Gets the stable ID for an object (for indexing purposes during deserialization) */ getStableId(obj) { const actualId = TUtils.getOrCreateIdForObject(obj); if (actualId) { return actualId; } return this.createPathBasedId(obj); } /** * Creates a path-based identifier (same logic as SerializationContext) */ createPathBasedId(obj) { if (obj === this.root) { return `@path:${obj.eClass().getName()}:@root`; } const path = []; let current = obj; while (current && current !== this.root) { const container = current.eContainer(); if (!container) break; for (const ref of container.eClass().getEAllReferences()) { if (ref.isContainment()) { const value = container.eGet(ref); if (ref.isMany()) { const list = value; const index = list.indexOf(current); if (index >= 0) { path.unshift(`${ref.getName()}[${index}]`); break; } } else if (value === current) { path.unshift(ref.getName()); break; } } } current = container; } return `@path:${obj.eClass().getName()}:/${path.join('/')}`; } /** * Resolves a path-based identifier to an object within the containment hierarchy. */ resolvePathBasedId(pathId) { // Check cache first const cached = this.pathToObject.get(pathId); if (cached) return cached; if (!pathId.startsWith('@path:')) { return undefined; } const parts = pathId.substring(6).split(':'); if (parts.length !== 2) return undefined; const [className, pathStr] = parts; if (pathStr === '@root') { const result = this.root.eClass().getName() === className ? this.root : undefined; if (result) this.pathToObject.set(pathId, result); return result; } // Parse the path const pathSegments = pathStr?.substring(1).split('/').filter(s => s.length > 0) || []; let current = this.root; for (const segment of pathSegments) { const match = segment.match(/^(.+?)(?:\[(\d+)\])?$/); if (!match) return undefined; const featureName = match[1]; const index = match[2] ? parseInt(match[2]) : undefined; if (!featureName) return undefined; const feature = current.eClass().getEStructuralFeature(featureName); if (!feature || !(feature instanceof EReferenceImpl) || !feature.isContainment()) { return undefined; } const value = current.eGet(feature); if (feature.isMany()) { if (index === undefined) return undefined; const list = value; if (index >= list.size()) return undefined; current = list.get(index); } else { if (!value) return undefined; current = value; } } // Verify the class name matches const result = current.eClass().getName() === className ? current : undefined; if (result) this.pathToObject.set(pathId, result); return result; } /** * Gets the index map for looking up objects by ID */ getIndex() { return this.idsToObjs; } /** * Resolves an ID to an object, handling both regular and path-based IDs */ resolveId(id) { // Try direct lookup first let obj = this.idsToObjs.get(id); // If not found and it's a path-based ID, try resolving it if (!obj && id.startsWith('@path:')) { obj = this.resolvePathBasedId(id); if (obj) { // Cache it for future lookups this.idsToObjs.set(id, obj); } } return obj; } } /** * Specialized SerializedReference for deserialization that holds the actual objects * instead of IDs, since we don't know the IDs yet during construction. */ class SerializedReferenceWithObject extends SerializedReference { fromObj; toIdOrPath; constructor(fromObj, toIdOrPath, refName) { super('', toIdOrPath, refName); this.fromObj = fromObj; this.toIdOrPath = toIdOrPath; } deserialize(context) { // Get the stable ID for the from object now that the hierarchy is complete const fromId = context.getStableId(this.fromObj); // The toIdOrPath is the serialized ID from the JSON const toObj = context.resolveId(this.toIdOrPath); if (this.fromObj && toObj) { const feature = this.fromObj.eClass().getEStructuralFeature(this.refName); if (feature) { if (feature.isMany()) { this.fromObj.eGet(feature).add(toObj); } else { this.fromObj.eSet(feature, toObj); } return true; } } return false; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGpzb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL2pzb24vdGpzb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBUUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN0QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDOUQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBRXRFOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxPQUFPLEtBQUs7SUFDaEIsc0VBQXNFO0lBQy9ELE1BQU0sQ0FBQywwQkFBMEIsR0FBRyxPQUFPLENBQUM7SUFFbkQseUZBQXlGO0lBQ3pGLE1BQU0sQ0FBQyxRQUFRLEdBQWdCLEVBQUUsQ0FBQztJQUMzQixNQUFNLENBQUMsV0FBVyxDQUFDLFFBQW9CO1FBQzVDLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO0lBQzNCLENBQUM7SUFFRCxvR0FBb0c7SUFDN0YsTUFBTSxDQUFDLFdBQVcsQ0FBQyxRQUFvQjtRQUM1QyxLQUFJLE1BQU0sQ0FBQyxJQUFJLFFBQVEsRUFBQyxDQUFDO1lBQ3ZCLElBQUcsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7Z0JBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdkQsQ0FBQztJQUNILENBQUM7SUFFRCxvQ0FBb0M7SUFDN0IsTUFBTSxDQUFDLFdBQVc7UUFDdkIsT0FBTyxLQUFLLENBQUMsUUFBUSxDQUFDO0lBQ3hCLENBQUM7SUFFRCxnREFBZ0Q7SUFDeEMsTUFBTSxDQUFDLG9CQUFvQjtRQUNqQyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQy9CLE9BQU8sQ0FBQyxJQUFJLENBQ1Ysb0VBQW9FO2dCQUNwRSxvRUFBb0UsQ0FDckUsQ0FBQztR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