1 import {Injectable} from '@angular/core';
3 // Added globally by /IDL2js
4 declare var _preload_fieldmapper_IDL: Object;
7 * Every IDL object class implements this interface.
9 export interface IdlObject {
12 _isfieldmapper: boolean;
13 // Dynamically appended functions from the IDL.
14 [fields: string]: any;
17 @Injectable({providedIn: 'root'})
18 export class IdlService {
20 classes: any = {}; // IDL class metadata
21 constructors = {}; // IDL instance generators
24 * Create a new IDL object instance.
26 create(cls: string, seed?: any[]): IdlObject {
27 if (this.constructors[cls]) {
28 return new this.constructors[cls](seed);
30 throw new Error(`No such IDL class ${cls}`);
36 this.classes = _preload_fieldmapper_IDL;
38 console.error('IDL (IDL2js) not found. Is the system running?');
43 * Creates the class constructor and getter/setter
44 * methods for each IDL class.
46 const mkclass = (cls, fields) => {
47 this.classes[cls].classname = cls;
49 // This dance lets us encode each IDL object with the
50 // IdlObject interface. Useful for adding type restrictions
51 // where desired for functions, etc.
52 const generator: any = ((): IdlObject => {
54 const x: any = function(seed) {
57 this._isfieldmapper = true;
60 fields.forEach(function(field, idx) {
61 x.prototype[field.name] = function(n) {
62 if (arguments.length === 1) {
69 field.label = field.name;
72 // Coerce 'aou' links to datatype org_unit for consistency.
73 if (field.datatype === 'link' && field.class === 'aou') {
74 field.datatype = 'org_unit';
81 this.constructors[cls] = generator();
83 // global class constructors required for JSON_v1.js
84 // TODO: polluting the window namespace w/ every IDL class
85 // is less than ideal.
86 window[cls] = this.constructors[cls];
89 Object.keys(this.classes).forEach(class_ => {
90 mkclass(class_, this.classes[class_].fields);
94 // Makes a deep copy of an IdlObject's / structures containing
95 // IdlObject's. Note we don't use JSON cross-walk because our
96 // JSON lib does not handle circular references.
97 // @depth specifies the maximum number of steps through IdlObject'
99 clone(source: any, depth?: number): any {
100 if (depth === undefined) {
105 if (typeof source === 'undefined' || source === null) {
108 } else if (source._isfieldmapper) {
109 // same depth because we're still cloning this same object
110 result = this.create(source.classname, this.clone(source.a, depth));
113 if (Array.isArray(source)) {
115 } else if (typeof source === 'object') { // source is not null
118 return source; // primitive
121 for (const j in source) {
122 if (source[j] === null || typeof source[j] === 'undefined') {
123 result[j] = source[j];
124 } else if (source[j]._isfieldmapper) {
126 result[j] = this.clone(source[j], depth - 1);
129 result[j] = this.clone(source[j], depth);