From 3041ca337e99019b8b75e6bf569eff3f638be5f1 Mon Sep 17 00:00:00 2001 From: Thomas Bouffard <27200110+tbouffard@users.noreply.github.com> Date: Mon, 11 Dec 2023 08:42:29 +0100 Subject: [PATCH] docs: improve JSDoc of codec classes (#287) In addition, apply minor refactoring - Codec.decodeCell: improve signature (default value) - ObjectCodec - use Codec type instead of value in import - simplify implementation of ObjectCodec.isNumericAttribute --- packages/core/src/serialization/Codec.ts | 62 ++++++-------- .../core/src/serialization/CodecRegistry.ts | 38 +++------ .../core/src/serialization/ObjectCodec.ts | 82 +++++++++---------- 3 files changed, 78 insertions(+), 104 deletions(-) diff --git a/packages/core/src/serialization/Codec.ts b/packages/core/src/serialization/Codec.ts index 85343b6a9..499166a7d 100644 --- a/packages/core/src/serialization/Codec.ts +++ b/packages/core/src/serialization/Codec.ts @@ -45,21 +45,19 @@ const createXmlDocument = () => { * The following code is used to encode a graph model. * * ```javascript - * var encoder = new Codec(); - * var result = encoder.encode(graph.getDataModel()); - * var xml = mxUtils.getXml(result); + * const encoder = new Codec(); + * const result = encoder.encode(graph.getDataModel()); + * const xml = mxUtils.getXml(result); * ``` * * #### Example * * Using the code below, an XML document is decoded into an existing model. The - * document may be obtained using one of the functions in mxUtils for loading - * an XML file, eg. {@link mxUtils.get}, or using {@link mxUtils.parseXml} for parsing an - * XML string. + * document may be obtained using {@link parseXml} for parsing an XML string. * * ```javascript - * var doc = mxUtils.parseXml(xmlString); - * var codec = new Codec(doc); + * const doc = xmlUtils.parseXml(xmlString); + * const codec = new Codec(doc); * codec.decode(doc.documentElement, graph.getDataModel()); * ``` * @@ -70,18 +68,17 @@ const createXmlDocument = () => { * be added anywhere in the cell hierarchy after parsing. * * ```javascript - * var xml = ''; - * var doc = mxUtils.parseXml(xml); - * var codec = new Codec(doc); - * var elt = doc.documentElement.firstChild; - * var cells = []; + * const xml = ''; + * const doc = mxUtils.parseXml(xml); + * const codec = new Codec(doc); + * let elt = doc.documentElement.firstChild; + * const cells = []; * * while (elt != null) * { * cells.push(codec.decode(elt)); * elt = elt.nextSibling; * } - * * graph.addCells(cells); * ``` * @@ -91,13 +88,13 @@ const createXmlDocument = () => { * output is displayed in a dialog box. * * ```javascript - * var enc = new Codec(); - * var cells = graph.getSelectionCells(); - * mxUtils.alert(mxUtils.getPrettyXml(enc.encode(cells))); + * const enc = new Codec(); + * const cells = graph.getSelectionCells(); + * const xml = xmlUtils.getPrettyXml(enc.encode(cells)); * ``` * * Newlines in the XML can be converted to
, in which case a '
' argument - * must be passed to {@link mxUtils.getXml} as the second argument. + * must be passed to {@link getXml} as the second argument. * * ### Debugging * @@ -105,11 +102,11 @@ const createXmlDocument = () => { * encoded objects: * * ```javascript - * var oldEncode = encode; + * const oldEncode = encode; * encode(obj) * { * MaxLog.show(); - * MaxLog.debug('Codec.encode: obj='+mxUtils.getFunctionName(obj.constructor)); + * MaxLog.debug('Codec.encode: obj='+StringUtils.getFunctionName(obj.constructor)); * * return oldEncode.apply(this, arguments); * }; @@ -146,7 +143,7 @@ class Codec { /** * Lookup table for resolving IDs to elements. */ - elements: any = null; // { [key: string]: Element } | null + elements: any = null; // TODO why not { [key: string]: Element } | null /** * Specifies if default values should be encoded. Default is false. @@ -154,7 +151,7 @@ class Codec { encodeDefaults = false; /** - * Assoiates the given object with the given ID and returns the given object. + * Associates the given object with the given ID and returns the given object. * * @param id ID for the object to be associated with. * @param obj Object to be associated with the ID. @@ -199,7 +196,7 @@ class Codec { * Example: * * ```javascript - * var codec = new Codec(); + * const codec = new Codec(); * codec.lookup(id) * { * return model.getCell(id); @@ -222,11 +219,6 @@ class Codec { return this.elements[id]; } - /** - * Returns the element with the given ID from {@link document}. - * - * @param id String that contains the ID. - */ updateElements(): void { if (this.elements == null) { this.elements = {}; @@ -299,7 +291,7 @@ class Codec { * Example: * * ```javascript - * var codec = new Codec(); + * const codec = new Codec(); * codec.reference(obj) * { * return obj.getCustomId(); @@ -313,8 +305,7 @@ class Codec { } /** - * Encodes the specified object and returns the resulting - * XML node. + * Encodes the specified object and returns the resulting XML node. * * @param obj Object to be encoded. */ @@ -345,7 +336,7 @@ class Codec { * the new instance if no object was given. * * @param node XML node to be decoded. - * @param into Optional object to be decodec into. + * @param into Optional object to be decoded into. */ decode(node: Element | null, into?: any): any { this.updateElements(); @@ -418,10 +409,9 @@ class Codec { * @param restoreStructures Optional boolean indicating whether * the graph structure should be restored by calling insert * and insertEdge on the parent and terminals, respectively. - * Default is true. + * Default is `true`. */ - decodeCell(node: Element, restoreStructures?: boolean): Cell { - restoreStructures = restoreStructures != null ? restoreStructures : true; + decodeCell(node: Element, restoreStructures = true): Cell { let cell = null; if (node != null && node.nodeType === NODETYPE.ELEMENT) { @@ -490,7 +480,7 @@ class Codec { * are not null. * * @param node XML node to set the attribute for. - * @param attributes Attributename to be set. + * @param attribute The name of the attribute to be set. * @param value New value of the attribute. */ setAttribute(node: Element, attribute: string, value: any): void { diff --git a/packages/core/src/serialization/CodecRegistry.ts b/packages/core/src/serialization/CodecRegistry.ts index 2c7a71fe2..d3f2b6722 100644 --- a/packages/core/src/serialization/CodecRegistry.ts +++ b/packages/core/src/serialization/CodecRegistry.ts @@ -21,12 +21,12 @@ import ObjectCodec from './ObjectCodec'; /** * Singleton class that acts as a global registry for codecs. * - * ### Adding an : + * ### Adding a Codec * * 1. Define a default codec with a new instance of the object to be handled. * * ```javascript - * var codec = new ObjectCodec(new Transactions()); + * const codec = new ObjectCodec(new Transactions()); * ``` * * 2. Define the functions required for encoding and decoding objects. @@ -36,36 +36,27 @@ import ObjectCodec from './ObjectCodec'; * codec.decode = function(dec: Codec, node: Element, into: any): any { ... } * ``` * - * 3. Register the codec in the . + * 3. Register the codec in the CodecRegistry. * * ```javascript * CodecRegistry.register(codec); * ``` * - * {@link ObjectCodec.decode} may be used to either create a new - * instance of an object or to configure an existing instance, - * in which case the into argument points to the existing - * object. In this case, we say the codec "configures" the - * object. - * - * @class CodecRegistry + * {@link ObjectCodec.decode} may be used to either create a new instance of an object or to configure an existing instance, + * in which case the into argument points to the existing object. In this case, we say the codec "configures" the object. */ class CodecRegistry { static codecs: { [key: string]: ObjectCodec | undefined } = {}; /** - * Maps from classnames to codecnames. - * @static + * Maps from classnames to codec names. */ static aliases: { [key: string]: string | undefined } = {}; /** - * Registers a new codec and associates the name of the template - * constructor in the codec with the codec object. + * Registers a new codec and associates the name of the template constructor in the codec with the codec object. * - * @static - * - * @param codec - {@link ObjectCodec} to be registered. + * @param codec ObjectCodec to be registered. */ static register(codec: ObjectCodec): ObjectCodec { if (codec != null) { @@ -81,20 +72,16 @@ class CodecRegistry { } /** - * Adds an alias for mapping a classname to a codecname. - * @static + * Adds an alias for mapping a classname to a codec name. */ static addAlias(classname: string, codecname: string): void { CodecRegistry.aliases[classname] = codecname; } /** - * Returns a codec that handles objects that are constructed - * using the given constructor. + * Returns a codec that handles objects that are constructed using the given constructor. * - * @static - * - * @param ctor - JavaScript constructor function. + * @param constructor_ JavaScript constructor function. */ static getCodec(constructor_: any): ObjectCodec | null { let codec = null; @@ -109,8 +96,7 @@ class CodecRegistry { codec = CodecRegistry.codecs[name] ?? null; - // Registers a new default codec for the given constructor - // if no codec has been previously defined. + // Registers a new default codec for the given constructor if no codec has been previously defined. if (codec == null) { try { codec = new ObjectCodec(new constructor_()); diff --git a/packages/core/src/serialization/ObjectCodec.ts b/packages/core/src/serialization/ObjectCodec.ts index d2be2841c..cfaba64ab 100644 --- a/packages/core/src/serialization/ObjectCodec.ts +++ b/packages/core/src/serialization/ObjectCodec.ts @@ -24,7 +24,7 @@ import { NODETYPE } from '../util/Constants'; import { isInteger, isNumeric } from '../util/mathUtils'; import { getTextContent } from '../util/domUtils'; import { load } from '../util/MaxXmlRequest'; -import Codec from './Codec'; +import type Codec from './Codec'; /** * Generic codec for JavaScript objects that implements a mapping between @@ -36,7 +36,7 @@ import Codec from './Codec'; * Consider the following example. * * ```javascript - * var obj = new Object(); + * const obj = new Object(); * obj.foo = "Foo"; * obj.bar = "Bar"; * ``` @@ -44,8 +44,8 @@ import Codec from './Codec'; * This object is encoded into an XML node using the following. * * ```javascript - * var enc = new Codec(); - * var node = enc.encode(obj); + * const enc = new Codec(); + * const node = enc.encode(obj); * ``` * * The output of the encoding may be viewed using {@link MaxLog} as follows. @@ -63,7 +63,7 @@ import Codec from './Codec'; * * In the above output, the foo and bar fields have been mapped to attributes * with the same names, and the name of the constructor was used for the - * nodename. + * node name. * * ### Booleans * @@ -75,15 +75,15 @@ import Codec from './Codec'; * * The above scheme is applied to all atomic fields, that is, to all non-object * fields of an object. For object fields, a child node is created with a - * special attribute that contains the fieldname. This special attribute is + * special attribute that contains the field name. This special attribute is * called "as" and hence, as is a reserved word that should not be used for a - * fieldname. + * field name. * * Consider the following example where foo is an object and bar is an atomic * property of foo. * * ```javascript - * var obj = {foo: {bar: "Bar"}}; + * const obj = {foo: {bar: "Bar"}}; * ``` * * This will be mapped to the following XML structure by ObjectCodec. @@ -95,13 +95,13 @@ import Codec from './Codec'; * ``` * * In the above output, the inner Object node contains the as-attribute that - * specifies the fieldname in the enclosing object. That is, the field foo was + * specifies the field name in the enclosing object. That is, the field foo was * mapped to a child node with an as-attribute that has the value foo. * * ### Arrays * * Arrays are special objects that are either associative, in which case each - * key, value pair is treated like a field where the key is the fieldname, or + * key, value pair is treated like a field where the key is the field name, or * they are a sequence of atomic values and objects, which is mapped to a * sequence of child nodes. For object elements, the above scheme is applied * without the use of the special as-attribute for creating each child. For @@ -113,7 +113,7 @@ import Codec from './Codec'; * called bar with an atomic value, and foo with an object value. * * ```javascript - * var obj = ["Bar", {bar: "Bar"}]; + * const obj = ["Bar", {bar: "Bar"}]; * obj["bar"] = "Bar"; * obj["foo"] = {bar: "Bar"}; * ``` @@ -139,7 +139,7 @@ import Codec from './Codec'; * which are used to lookup the object in a table within {@link Codec}. The * {@link isReference} function is in charge of deciding if a specific field should * be encoded as a reference or not. Its default implementation returns true if - * the fieldname is in {@link idrefs}, an array of strings that is used to configure + * the field name is in {@link idrefs}, an array of strings that is used to configure * the {@link ObjectCodec}. * * Using this approach, the mapping does not guarantee that the referenced @@ -174,11 +174,11 @@ import Codec from './Codec'; * For decoding JavaScript expressions, the add-node may be used with a text * content that contains the JavaScript expression. For example, the following * creates a field called foo in the enclosing object and assigns it the value - * of {@link mxConstants.ALIGN_LEFT}. + * of {@link Constants.ALIGN.LEFT}. * * ```javascript * - * mxConstants.ALIGN_LEFT + * Constants.ALIGN.LEFT * * ``` * @@ -195,8 +195,6 @@ import Codec from './Codec'; * functions on the resulting object. * * Expressions are only evaluated if {@link allowEval} is true. - * - * @class ObjectCodec */ class ObjectCodec { constructor( @@ -220,8 +218,9 @@ class ObjectCodec { /** * Static global switch that specifies if expressions in arrays are allowed. - * Default is false. NOTE: Enabling this carries a possible security risk. - * @static + * + * **NOTE**: Enabling this carries a possible security risk. + * @default false */ static allowEval = false; @@ -231,8 +230,7 @@ class ObjectCodec { template: any; /** - * Array containing the variable names that should be - * ignored by the codec. + * Array containing the variable names that should be ignored by the codec. */ exclude: string[]; @@ -244,21 +242,22 @@ class ObjectCodec { idrefs: string[]; /** - * Maps from from fieldnames to XML attribute names. + * Maps from field names to XML attribute names. */ mapping: { [key: string]: string }; /** - * Maps from from XML attribute names to fieldnames. + * Maps from XML attribute names to fieldnames. */ reverse: { [key: string]: string }; /** - * Returns the name used for the nodenames and lookup of the codec when + * Returns the name used for the node names and lookup of the codec when * classes are encoded and nodes are decoded. For classes to work with * this the codec registry automatically adds an alias for the classname - * if that is different than what this returns. The default implementation - * returns the classname of the template class. + * if that is different from what this returns. + * + * The default implementation returns the classname of the template class. */ getName(): string { return this.template.constructor.name; @@ -272,7 +271,7 @@ class ObjectCodec { } /** - * Returns the fieldname for the given attributename. + * Returns the field name for the given attribute name. * Looks up the value in the {@link reverse} mapping or returns * the input if there is no reverse mapping for the * given name. @@ -290,7 +289,7 @@ class ObjectCodec { } /** - * Returns the attributename for the given fieldname. + * Returns the attribute name for the given field name. * Looks up the value in the {@link mapping} or returns * the input if there is no mapping for the * given name. @@ -308,8 +307,8 @@ class ObjectCodec { /** * Returns true if the given attribute is to be ignored by the codec. This - * implementation returns true if the given fieldname is in {@link exclude} or - * if the fieldname equals {@link ObjectIdentity.FIELD_NAME}. + * implementation returns true if the given field name is in {@link exclude} or + * if the field name equals {@link ObjectIdentity.FIELD_NAME}. * * @param obj Object instance that contains the field. * @param attr Fieldname of the field. @@ -322,12 +321,12 @@ class ObjectCodec { } /** - * Returns true if the given fieldname is to be treated + * Returns true if the given field name is to be treated * as a textual reference (ID). This implementation returns - * true if the given fieldname is in {@link idrefs}. + * true if the given field name is in {@link idrefs}. * * @param obj Object instance that contains the field. - * @param attr Fieldname of the field. + * @param attr Field name of the field. * @param value Value of the field. * @param write Boolean indicating if the field is being encoded or decoded. * Write is true if the field is being encoded, else it is being decoded. @@ -545,7 +544,7 @@ class ObjectCodec { * Returns true if the given object attribute is a boolean value. * * @param enc {@link Codec} that controls the encoding process. - * @param obj Objec to convert the attribute for. + * @param obj Object to convert the attribute for. * @param name Name of the attribute to be converted. * @param value Value of the attribute to be converted. */ @@ -580,20 +579,19 @@ class ObjectCodec { * * @param dec {@link Codec} that controls the decoding process. * @param attr XML attribute to be converted. - * @param obj Objec to convert the attribute for. + * @param obj Object to convert the attribute for. */ isNumericAttribute(dec: Codec, attr: any, obj: any): boolean { // Handles known numeric attributes for generic objects - const result = + return ( (obj.constructor === Geometry && (attr.name === 'x' || attr.name === 'y' || attr.name === 'width' || attr.name === 'height')) || (obj.constructor === Point && (attr.name === 'x' || attr.name === 'y')) || - isNumeric(attr.value); - - return result; + isNumeric(attr.value) + ); } /** @@ -711,7 +709,7 @@ class ObjectCodec { * * @param dec {@link Codec} that controls the decoding process. * @param node XML node to be decoded. - * @param obj Objec to encode the node into. + * @param obj Object to encode the node into. */ decodeAttributes(dec: Codec, node: Element, obj: any): void { const attrs = node.attributes; @@ -847,8 +845,8 @@ class ObjectCodec { /** * Sets the decoded child node as a value of the given object. If the - * object is a map, then the value is added with the given fieldname as a - * key. If the fieldname is not empty, then setFieldValue is called or + * object is a map, then the value is added with the given field name as a + * key. If the field name is not empty, then setFieldValue is called or * else, if the object is a collection, the value is added to the * collection. For strongly typed languages it may be required to * override this with the correct code to add an entry to an object. @@ -915,7 +913,7 @@ class ObjectCodec { * without any changes. The return value of this method * is returned to the decoder from {@link decode}. * - * @param enc {@link Codec} that controls the encoding process. + * @param dec {@link Codec} that controls the encoding process. * @param node XML node to be decoded. * @param obj Object that represents the default decoding. */