From 031c924f152f7ed4fe6f54e9c8d59f3a8fe002fe Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Fri, 27 Dec 2024 14:30:46 +0800 Subject: [PATCH 01/10] Init commit --- rosidl_gen/templates/message.dot | 150 ++++++++++++++++--------------- 1 file changed, 77 insertions(+), 73 deletions(-) diff --git a/rosidl_gen/templates/message.dot b/rosidl_gen/templates/message.dot index d9160eff..195b83a2 100644 --- a/rosidl_gen/templates/message.dot +++ b/rosidl_gen/templates/message.dot @@ -31,7 +31,7 @@ if (it.spec.fields.length === 0) { }, "name": "_dummy" }); -} /* if */ +} function getPrimitiveNameByType(type) { if (type.type === 'bool') { @@ -108,7 +108,6 @@ function getTypedArrayName(type) { default: typedArrayName = ''; } - return typedArrayName; } @@ -267,80 +266,84 @@ const {{=refObjectArrayType}} = StructType({ capacity: ref.types.size_t }); -// Define the wrapper class. +{{/* Define the wrapper class for the message. */}} class {{=objectWrapper}} { constructor(other, willCheckConsistency = false) { - this._wrapperFields = {}; - this._willCheckConsistency = willCheckConsistency; - {{~ it.spec.fields :field}} - {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} - this._{{=field.name}}Array = []; - {{?}} - {{~}} + this._initMembers(willCheckConsistency); + this._setDefaults(); + {{/* Construct `this` from `other`. */}} if (typeof other === 'object' && other._refObject) { + //this._initMembers(willCheckConsistency); this._refObject = new {{=refObjectType}}(other._refObject.toObject()); {{~ it.spec.fields :field}} - {{? field.type.isPrimitiveType && !field.type.isArray}} - this._{{=field.name}}Intialized = true; - {{?}} - - {{? field.type.isArray}} - this._wrapperFields.{{=field.name}} = {{=getWrapperNameByType(field.type)}}.createArray(); - this._wrapperFields.{{=field.name}}.copy(other._wrapperFields.{{=field.name}}); - {{? field.type.isPrimitiveType && !isTypedArrayType(field.type)}} - this.{{=field.name}} = other.{{=field.name}}; - {{?}} - {{?? !field.type.isPrimitiveType || (field.type.type === 'string' && it.spec.msgName !== 'String')}} - this._wrapperFields.{{=field.name}} = new {{=getWrapperNameByType(field.type)}}(other._wrapperFields.{{=field.name}}); - {{?}} + {{? field.type.isPrimitiveType && !field.type.isArray}} + this._{{=field.name}}Intialized = true; + {{?}} + + {{? field.type.isArray}} + this._wrapperFields.{{=field.name}} = {{=getWrapperNameByType(field.type)}}.createArray(); + this._wrapperFields.{{=field.name}}.copy(other._wrapperFields.{{=field.name}}); + {{? field.type.isPrimitiveType && !isTypedArrayType(field.type)}} + this.{{=field.name}} = other.{{=field.name}}; + {{?}} + {{?? !field.type.isPrimitiveType || (field.type.type === 'string' && it.spec.msgName !== 'String')}} + this._wrapperFields.{{=field.name}} = new {{=getWrapperNameByType(field.type)}}(other._wrapperFields.{{=field.name}}); + {{?}} {{~}} } else if (typeof other !== 'undefined') { - this._initMembers(); + {{/* Try to construct the message from a plan object of JavaScript. */}} + //this._initMembers(willCheckConsistency); translator.constructFromPlanObject(this, other); } else { - this._initMembers(); + //this._initMembers(willCheckConsistency); } this.freeze(); } - _initMembers() { - this._refObject = new {{=refObjectType}}(); + _setDefaults() { {{~ it.spec.fields :field}} - {{? it.spec.isEmpty}} - this._{{=field.name}}Intialized = true; - {{??}} - {{? field.type.isPrimitiveType && !field.type.isArray}} - {{? field.default_value === null}} - this._{{=field.name}}Intialized = false; - {{?? field.type.type === 'string' || field.type.type === 'wstring'}} - this._refObject.{{=field.name}} = "{{=field.default_value.replace(/"/g, '\\"')}}"; - this._{{=field.name}}Intialized = true; - {{??}} - this._refObject.{{=field.name}} = {{=field.default_value}}; - this._{{=field.name}}Intialized = true; - {{?}} - {{?}} + {{/* Set the flag of initialization. */}} + {{? it.spec.isEmpty}} + this._{{=field.name}}Intialized = true; + {{?? field.type.isPrimitiveType && !field.type.isArray && field.default_value}} + this._{{=field.name}}Intialized = true; + {{? field.type.type === 'string' || field.type.type === 'wstring'}} + this._refObject.{{=field.name}} = "{{=field.default_value.replace(/"/g, '\\"')}}"; + {{??}} + this._refObject.{{=field.name}} = {{=field.default_value}}; + {{?}} + {{?? field.type.isPrimitiveType && !isTypedArrayType(field.type) && field.default_value}} + this._{{=field.name}}Array = {{=JSON.stringify(field.default_value)}}; + {{?? field.type.isPrimitiveType && isTypedArrayType(field.type) && field.default_value}} + this._wrapperFields.{{=field.name}}.fill({{=getTypedArrayName(field.type)}}.from({{=JSON.stringify(field.default_value)}})); + {{??}} + this._{{=field.name}}Intialized = false; + {{?}} + {{~}} + } - {{? field.type.isArray}} - this._wrapperFields.{{=field.name}} = {{=getWrapperNameByType(field.type)}}.createArray(); - {{? field.default_value !== null && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} - this._{{=field.name}}Array = {{=JSON.stringify(field.default_value)}}; - {{?}} - {{? field.default_value !== null && field.type.isPrimitiveType && isTypedArrayType(field.type)}} - this._wrapperFields.{{=field.name}}.fill({{=getTypedArrayName(field.type)}}.from({{=JSON.stringify(field.default_value)}})); - {{?}} - {{? field.type.type === 'string' && field.type.isFixedSizeArray}} - for (let i = 0; i < {{=field.type.arraySize}}; i++) { - primitiveTypes.initString(this._refObject.{{=field.name}}[i]); - } - {{?}} - {{?? !field.type.isPrimitiveType || (field.type.type === 'string' && it.spec.msgName !== 'String')}} - this._wrapperFields.{{=field.name}} = new {{=getWrapperNameByType(field.type)}}(); - {{?? it.spec.msgName === 'String'}} - primitiveTypes.initString(this._refObject); - {{?}} - {{?}} + _initMembers(willCheckConsistency) { + this._willCheckConsistency = willCheckConsistency; + this._wrapperFields = {}; + this._refObject = new {{=refObjectType}}(); + + {{~ it.spec.fields :field}} + {{? field.type.isArray}} + this._wrapperFields.{{=field.name}} = {{=getWrapperNameByType(field.type)}}.createArray(); + {{? field.type.type === 'string' && field.type.isFixedSizeArray}} + for (let i = 0; i < {{=field.type.arraySize}}; i++) { + primitiveTypes.initString(this._refObject.{{=field.name}}[i]); + } + {{?}} + {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} + this._{{=field.name}}Array = []; + {{?}} + {{?? !field.type.isPrimitiveType || (field.type.type === 'string' && it.spec.msgName !== 'String')}} + this._wrapperFields.{{=field.name}} = new {{=getWrapperNameByType(field.type)}}(); + {{?? it.spec.msgName === 'String'}} + primitiveTypes.initString(this._refObject); + {{?}} {{~}} } @@ -371,6 +374,7 @@ class {{=objectWrapper}} { return this._refObject.ref(); } + {{ /*Allocate the memory following the struct of the message*/ }} freeze(own = false, checkConsistency = false) { {{~ it.spec.fields :field}} {{? field.type.isPrimitiveType && !field.type.isArray}} @@ -395,7 +399,7 @@ class {{=objectWrapper}} { } } } - // For non-typed array like int64/uint64/bool. + {{/* For non-typed array like int64/uint64/bool. */}} {{?? true}} this._refObject.{{=field.name}} = this._{{=field.name}}Array; {{?}} @@ -459,7 +463,7 @@ class {{=objectWrapper}} { for (let index = 0; index < {{=field.type.arraySize}}; index++) { this._{{=field.name}}Array[index] = refObject.{{=field.name}}[index].data; } - // For non-typed array like int64/uint64/bool. + {{/* For non-typed array like int64/uint64/bool. */}} {{?? true}} this._{{=field.name}}Array = refObject.{{=field.name}}.toArray(); {{?}} @@ -494,7 +498,7 @@ class {{=objectWrapper}} { if (refObject.{{=field.name}}.size != 0) { {{=getWrapperNameByType(field.type)}}.ArrayType.freeArray(refObject.{{=field.name}}); if ({{=getWrapperNameByType(field.type)}}.ArrayType.useTypedArray) { - // Do nothing, the v8 will take the ownership of the ArrayBuffer used by the typed array. + {{/* Do nothing, the v8 will take the ownership of the ArrayBuffer used by the typed array. */}} } else { deallocator.freeStructMember(refObject.{{=field.name}}, {{=getWrapperNameByType(field.type)}}.refObjectArrayType, 'data'); } @@ -657,7 +661,7 @@ class {{=objectWrapper}} { } } -// Define the wrapper of array class. +{{/* Define the wrapper class for the message array. */}} class {{=arrayWrapper}} { constructor(size = 0) { this._resize(size); @@ -670,13 +674,13 @@ class {{=arrayWrapper}} { fill(values) { {{? usePlainTypedArray}} if (Array.isArray(values)) { - // Convert JavaScript array + {{/* Convert JavaScript array. */}} this._wrappers = new {{=currentTypedArray}}(values); } else { this._wrappers = values; } {{?? isPrimitivePackage(it.spec.baseType)}} - // Now for primitive arrays, only string/bool/int64/uint64 array drops here. + {{/* For primitive arrays, only string/bool/int64/uint64 array drops here. */}} const length = values.length; this._resize(length); for (let i = 0; i < length; ++i) { @@ -697,10 +701,10 @@ class {{=arrayWrapper}} { {{?}} } - // Put all data currently stored in `this._wrappers` into `this._refObject` + {{/* Put all data currently stored in `this._wrappers` into `this._refObject`. */}} freeze(own) { {{? usePlainTypedArray}} - // When it's a TypedArray: no need to copy to `this._refArray` + {{/* When it's a TypedArray: no need to copy to `this._refArray`. */}} {{?? true}} this._wrappers.forEach((wrapper, index) => { wrapper.freeze(own); @@ -783,13 +787,13 @@ class {{=arrayWrapper}} { {{?}} } - // Copy all data from `this._refObject` into `this._wrappers` + {{/* Copy all data from `this._refObject` into `this._wrappers`. */}} copyRefObject(refObject) { this._refObject = refObject; {{? usePlainTypedArray}} const byteLen = refObject.size * ref.types.{{=currentTypedArrayElementType}}.size; - // An ArrayBuffer object that doesn't hold the ownership of the address + {{/* An ArrayBuffer object doesn't hold the ownership of memory block starting from address. */}} const arrayBuffer = refObject.data.length !== 0 ? rclnodejs.createArrayBufferFromAddress(refObject.data.hexAddress(), byteLen) : Buffer.alloc(0); @@ -814,7 +818,7 @@ class {{=arrayWrapper}} { {{? usePlainTypedArray}} this._wrappers = other._wrappers.slice(); {{?? true}} - // Array deep copy + {{/* Array deep copy. */}} other._wrappers.forEach((wrapper, index) => { this._wrappers[index].copy(wrapper); }); @@ -823,7 +827,7 @@ class {{=arrayWrapper}} { static freeArray(refObject) { {{? usePlainTypedArray}} - // For TypedArray: .data will be 'free()'-ed in parent struct + {{/* For TypedArray, `.data` will be 'free()'-ed in parent struct. */}} {{?? true}} let refObjectArray = refObject.data; refObjectArray.length = refObject.size; @@ -851,7 +855,7 @@ class {{=arrayWrapper}} { } {{? it.spec.constants != undefined && it.spec.constants.length}} -// Define constants ({{=it.spec.constants.length}} in total) +{{/* Define constants ({{=it.spec.constants.length}} in total). */}} {{~ it.spec.constants :c}} {{? c.type === "string"}} Object.defineProperty({{=objectWrapper}}, "{{=c.name}}", {value: "{{=c.value}}", writable: false, enumerable: true, configurable: true}); From 7215440e3657b6445b1d0808ff4a0c8bae37ea7a Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Mon, 30 Dec 2024 17:42:52 +0800 Subject: [PATCH 02/10] Follow-up change --- package.json | 4 +- rosidl_gen/idl_generator.js | 4 + rosidl_gen/templates/message.dot | 220 +++++++++++++++---------------- 3 files changed, 109 insertions(+), 119 deletions(-) diff --git a/package.json b/package.json index d232e821..bebac438 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,6 @@ "jsdoc": "^4.0.4", "lint-staged": "^15.2.10", "mocha": "^11.0.2", - "prettier": "^3.4.2", "sinon": "^19.0.2", "tree-kill": "^1.2.2", "typescript": "^5.7.2" @@ -83,7 +82,8 @@ "nan": "^2.22.0", "rimraf": "^6.0.1", "uuid": "^11.0.3", - "walk": "^2.3.15" + "walk": "^2.3.15", + "prettier": "^3.4.2" }, "husky": { "hooks": { diff --git a/rosidl_gen/idl_generator.js b/rosidl_gen/idl_generator.js index f09674f2..598721ee 100644 --- a/rosidl_gen/idl_generator.js +++ b/rosidl_gen/idl_generator.js @@ -15,6 +15,7 @@ 'use strict'; const dot = require('dot'); +const prettier = require('prettier'); const fse = require('fs-extra'); const path = require('path'); const parser = require('../rosidl_parser/rosidl_parser.js'); @@ -40,6 +41,9 @@ function removeEmptyLines(str) { * @param {string} code */ async function writeGeneratedCode(dir, fileName, code) { + if (fileName.endsWith('.js')) { + code = await prettier.format(code, { singleQuote: true, parser: 'babel' }); + } await fse.mkdirs(dir); await fse.writeFile(path.join(dir, fileName), code); } diff --git a/rosidl_gen/templates/message.dot b/rosidl_gen/templates/message.dot index 195b83a2..10ef4320 100644 --- a/rosidl_gen/templates/message.dot +++ b/rosidl_gen/templates/message.dot @@ -271,16 +271,14 @@ class {{=objectWrapper}} { constructor(other, willCheckConsistency = false) { this._initMembers(willCheckConsistency); this._setDefaults(); - {{/* Construct `this` from `other`. */}} + {{/* Construct `this` from `other`. */}} if (typeof other === 'object' && other._refObject) { - //this._initMembers(willCheckConsistency); this._refObject = new {{=refObjectType}}(other._refObject.toObject()); {{~ it.spec.fields :field}} {{? field.type.isPrimitiveType && !field.type.isArray}} this._{{=field.name}}Intialized = true; {{?}} - {{? field.type.isArray}} this._wrapperFields.{{=field.name}} = {{=getWrapperNameByType(field.type)}}.createArray(); this._wrapperFields.{{=field.name}}.copy(other._wrapperFields.{{=field.name}}); @@ -293,10 +291,7 @@ class {{=objectWrapper}} { {{~}} } else if (typeof other !== 'undefined') { {{/* Try to construct the message from a plan object of JavaScript. */}} - //this._initMembers(willCheckConsistency); translator.constructFromPlanObject(this, other); - } else { - //this._initMembers(willCheckConsistency); } this.freeze(); } @@ -370,7 +365,7 @@ class {{=objectWrapper}} { } toRawROS() { - this.freeze(true); + this.freeze(/*own=*/true); return this._refObject.ref(); } @@ -385,63 +380,63 @@ class {{=objectWrapper}} { {{~}} {{~ it.spec.fields :field}} - {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type) && field.type.isFixedSizeArray }} - {{? field.type.type === 'string'}} - for (let i = 0; i < {{=field.type.arraySize}}; i++) { - if (own) { - primitiveTypes.initString(this._refObject.{{=field.name}}[i].ref(), own); + {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type) && field.type.isFixedSizeArray}} + {{? field.type.type === 'string'}} + for (let i = 0; i < {{=field.type.arraySize}}; i++) { + if (own) { + primitiveTypes.initString(this._refObject.{{=field.name}}[i].ref(), own); + } else { + if (this._{{=field.name}}Array.length === {{=field.type.arraySize}}) { + const value = this._{{=field.name}}Array[i]; + this._refObject.{{=field.name}}[i].data = value; + this._refObject.{{=field.name}}[i].size = Buffer.byteLength(value); + this._refObject.{{=field.name}}[i].capacity = Buffer.byteLength(value) + 1; + } + } + } + {{/* For non-typed array like int64/uint64/bool. */}} + {{??}} + this._refObject.{{=field.name}} = this._{{=field.name}}Array; + {{?}} + {{?? field.type.isArray && field.type.isPrimitiveType && isTypedArrayType(field.type) && field.type.isFixedSizeArray}} + this._refObject.{{=field.name}} = Array.from(this._wrapperFields.{{=field.name}}.data); + {{?? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} + if (!own) { + this._wrapperFields.{{=field.name}}.fill(this._{{=field.name}}Array); + this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); + this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; } else { - if (this._{{=field.name}}Array.length === {{=field.type.arraySize}}) { - const value = this._{{=field.name}}Array[i]; - this._refObject.{{=field.name}}[i].data = value; - this._refObject.{{=field.name}}[i].size = Buffer.byteLength(value); - this._refObject.{{=field.name}}[i].capacity = Buffer.byteLength(value) + 1; + this._wrapperFields.{{=field.name}}.fill([]); + this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); + this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; + } + {{?? field.type.isArray && !field.type.isPrimitiveType && field.type.isFixedSizeArray}} + for (let i = 0; i < {{=field.type.arraySize}}; i++) { + if (this._wrapperFields.{{=field.name}}.data[i]) { + this._wrapperFields.{{=field.name}}.data[i].freeze(own, checkConsistency); + this._refObject.{{=field.name}}[i] = this._wrapperFields.{{=field.name}}.data[i].refObject; } } - } - {{/* For non-typed array like int64/uint64/bool. */}} - {{?? true}} - this._refObject.{{=field.name}} = this._{{=field.name}}Array; - {{?}} - {{?? field.type.isArray && field.type.isPrimitiveType && isTypedArrayType(field.type) && field.type.isFixedSizeArray}} - this._refObject.{{=field.name}} = Array.from(this._wrapperFields.{{=field.name}}.data); - {{?? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} - if (!own) { - this._wrapperFields.{{=field.name}}.fill(this._{{=field.name}}Array); - this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); - this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; - } else { - this._wrapperFields.{{=field.name}}.fill([]); + {{?? !field.type.isPrimitiveType || field.type.isArray}} this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; - } - {{?? field.type.isArray && !field.type.isPrimitiveType && field.type.isFixedSizeArray}} - for (let i = 0; i < {{=field.type.arraySize}}; i++) { - if (this._wrapperFields.{{=field.name}}.data[i]) { - this._wrapperFields.{{=field.name}}.data[i].freeze(own, checkConsistency); - this._refObject.{{=field.name}}[i] = this._wrapperFields.{{=field.name}}.data[i].refObject; + {{? field.type.isArray && field.type.isPrimitiveType}} + if (own) { + this._wrapperFields.{{=field.name}}.fill({{=getTypedArrayName(field.type)}}.from([])); + this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); + this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; + } + {{?}} + {{?? field.type.type === 'string' && it.spec.msgName !== 'String'}} + if (own) { + this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); } - } - {{?? !field.type.isPrimitiveType || field.type.isArray}} - this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); - this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; - {{? field.type.isArray && field.type.isPrimitiveType }} - if (own) { - this._wrapperFields.{{=field.name}}.fill({{=getTypedArrayName(field.type)}}.from([])); - this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; - } - {{?}} - {{?? field.type.type === 'string' && it.spec.msgName !== 'String'}} - if (own) { - this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); - } - this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; - {{?? it.spec.msgName === 'String'}} - if (own) { - primitiveTypes.initString(this._refObject.ref(), own); - } - {{?}} + {{?? it.spec.msgName === 'String'}} + if (own) { + primitiveTypes.initString(this._refObject.ref(), own); + } + {{?}} {{~}} } @@ -452,21 +447,19 @@ class {{=objectWrapper}} { deserialize(refObject) { {{~ it.spec.fields :field}} - {{? field.type.isPrimitiveType && !field.type.isArray}} this._{{=field.name}}Intialized = true; - {{?}} {{? field.type.isArray && field.type.isPrimitiveType && field.type.isFixedSizeArray && isTypedArrayType(field.type)}} this._wrapperFields.{{=field.name}}.fill(refObject.{{=field.name}}.toArray()); {{?? field.type.isArray && field.type.isPrimitiveType && field.type.isFixedSizeArray && !isTypedArrayType(field.type)}} - {{? field.type.type === 'string' }} - for (let index = 0; index < {{=field.type.arraySize}}; index++) { - this._{{=field.name}}Array[index] = refObject.{{=field.name}}[index].data; - } - {{/* For non-typed array like int64/uint64/bool. */}} - {{?? true}} - this._{{=field.name}}Array = refObject.{{=field.name}}.toArray(); - {{?}} + {{? field.type.type === 'string'}} + for (let index = 0; index < {{=field.type.arraySize}}; index++) { + this._{{=field.name}}Array[index] = refObject.{{=field.name}}[index].data; + } + {{/* For non-typed array like int64/uint64/bool. */}} + {{??}} + this._{{=field.name}}Array = refObject.{{=field.name}}.toArray(); + {{?}} {{?? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} refObject.{{=field.name}}.data.length = refObject.{{=field.name}}.size; for (let index = 0; index < refObject.{{=field.name}}.size; index++) { @@ -556,7 +549,7 @@ class {{=objectWrapper}} { return undefined; } return this._wrapperFields.{{=field.name}}.data; - {{?? true}} + {{??}} if (!this._{{=field.name}}Intialized) { return undefined; } @@ -594,11 +587,11 @@ class {{=objectWrapper}} { } {{?? !field.type.isArray && field.type.type === 'string' && it.spec.msgName !== 'String'}} this._wrapperFields.{{=field.name}}.data = value; - {{?? true}} - {{? it.spec.msgName === 'String'}} - this._refObject.size = Buffer.byteLength(value); - this._refObject.capacity = Buffer.byteLength(value) + 1; - {{?}} + {{??}} + {{? it.spec.msgName === 'String'}} + this._refObject.size = Buffer.byteLength(value); + this._refObject.capacity = Buffer.byteLength(value) + 1; + {{?}} this._refObject.{{=field.name}} = value; {{?}} } @@ -608,26 +601,23 @@ class {{=objectWrapper}} { this._refObject = new {{=refObjectType}}(refObject.toObject()); {{~ it.spec.fields :field}} - {{? field.type.isPrimitiveType && !field.type.isArray}} - this._{{=field.name}}Intialized = true; - {{?}} - - {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} - refObject.{{=field.name}}.data.length = refObject.{{=field.name}}.size; - for (let index = 0; index < refObject.{{=field.name}}.size; index++) { - this._{{=field.name}}Array[index] = refObject.{{=field.name}}.data[index].data; - } - {{?? field.type.isArray && field.type.isPrimitiveType && field.type.isFixedSizeArray}} - this._wrapperFields.{{=field.name}}.fill(refObject.{{=field.name}}.toArray()); - {{?? field.type.isArray && !field.type.isPrimitiveType && field.type.isFixedSizeArray}} - this._refObject.{{=field.name}} = refObject.{{=field.name}}; - this._wrapperFields.{{=field.name}}.size = {{=field.type.arraySize}} - for (let i = 0; i < {{=field.type.arraySize}}; i++) { - this._wrapperFields.{{=field.name}}.data[i].copyRefObject(refObject.{{=field.name}}[i]); - } - {{?? !field.type.isPrimitiveType || field.type.isArray || (field.type.type === 'string' && it.spec.msgName !== 'String')}} - this._wrapperFields.{{=field.name}}.copyRefObject(this._refObject.{{=field.name}}); - {{?}} + this._{{=field.name}}Intialized = true; + {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} + refObject.{{=field.name}}.data.length = refObject.{{=field.name}}.size; + for (let index = 0; index < refObject.{{=field.name}}.size; index++) { + this._{{=field.name}}Array[index] = refObject.{{=field.name}}.data[index].data; + } + {{?? field.type.isArray && field.type.isPrimitiveType && field.type.isFixedSizeArray}} + this._wrapperFields.{{=field.name}}.fill(refObject.{{=field.name}}.toArray()); + {{?? field.type.isArray && !field.type.isPrimitiveType && field.type.isFixedSizeArray}} + this._refObject.{{=field.name}} = refObject.{{=field.name}}; + this._wrapperFields.{{=field.name}}.size = {{=field.type.arraySize}} + for (let i = 0; i < {{=field.type.arraySize}}; i++) { + this._wrapperFields.{{=field.name}}.data[i].copyRefObject(refObject.{{=field.name}}[i]); + } + {{?? !field.type.isPrimitiveType || field.type.isArray || (field.type.type === 'string' && it.spec.msgName !== 'String')}} + this._wrapperFields.{{=field.name}}.copyRefObject(this._refObject.{{=field.name}}); + {{?}} {{~}} } @@ -635,15 +625,12 @@ class {{=objectWrapper}} { this._refObject = new {{=refObjectType}}(other._refObject.toObject()); {{~ it.spec.fields :field}} - {{? field.type.isPrimitiveType && !field.type.isArray}} - this._{{=field.name}}Intialized = true; - {{?}} - - {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} - this._{{=field.name}}Array = other._{{=field.name}}Array.slice(); - {{?? !field.type.isPrimitiveType || field.type.isArray || (field.type.type === 'string' && it.spec.msgName !== 'String')}} - this._wrapperFields.{{=field.name}}.copy(other._wrapperFields.{{=field.name}}); - {{?}} + this._{{=field.name}}Intialized = true; + {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} + this._{{=field.name}}Array = other._{{=field.name}}Array.slice(); + {{?? !field.type.isPrimitiveType || field.type.isArray || (field.type.type === 'string' && it.spec.msgName !== 'String')}} + this._wrapperFields.{{=field.name}}.copy(other._wrapperFields.{{=field.name}}); + {{?}} {{~}} } @@ -688,7 +675,7 @@ class {{=arrayWrapper}} { wrapper.data = values[i]; this._wrappers[i] = wrapper; } - {{?? true}} + {{??}} const length = values.length; this._resize(length); values.forEach((value, index) => { @@ -705,7 +692,7 @@ class {{=arrayWrapper}} { freeze(own) { {{? usePlainTypedArray}} {{/* When it's a TypedArray: no need to copy to `this._refArray`. */}} - {{?? true}} + {{??}} this._wrappers.forEach((wrapper, index) => { wrapper.freeze(own); this._refArray[index] = wrapper.refObject; @@ -718,12 +705,12 @@ class {{=arrayWrapper}} { if (this._refObject.capacity === 0) { this._refObject.data = null } else { - {{? usePlainTypedArray}} - const buffer = Buffer.from(new Uint8Array(this._wrappers.buffer)); - this._refObject.data = buffer; - {{?? true}} - this._refObject.data = this._refArray.buffer; - {{?}} + {{? usePlainTypedArray}} + const buffer = Buffer.from(new Uint8Array(this._wrappers.buffer)); + this._refObject.data = buffer; + {{?? true}} + this._refObject.data = this._refArray.buffer; + {{?}} } } @@ -769,7 +756,7 @@ class {{=arrayWrapper}} { } {{? usePlainTypedArray}} this._refArray = undefined; - {{?? true}} + {{??}} this._refArray = new {{=refArrayType}}(size); {{?}} @@ -779,7 +766,7 @@ class {{=arrayWrapper}} { {{? usePlainTypedArray}} this._wrappers = new {{=currentTypedArray}}(size); - {{?? true}} + {{??}} this._wrappers = new Array(); for (let i = 0; i < size; i++) { this._wrappers.push(new {{=objectWrapper}}()); @@ -798,11 +785,10 @@ class {{=arrayWrapper}} { rclnodejs.createArrayBufferFromAddress(refObject.data.hexAddress(), byteLen) : Buffer.alloc(0); this._wrappers = new {{=currentTypedArray}}(arrayBuffer); - {{?? true}} + {{??}} let refObjectArray = this._refObject.data; refObjectArray.length = this._refObject.size; this._resize(this._refObject.size); - for (let index = 0; index < this._refObject.size; index++) { this._wrappers[index].copyRefObject(refObjectArray[index]); } @@ -817,7 +803,7 @@ class {{=arrayWrapper}} { this._resize(other.size); {{? usePlainTypedArray}} this._wrappers = other._wrappers.slice(); - {{?? true}} + {{??}} {{/* Array deep copy. */}} other._wrappers.forEach((wrapper, index) => { this._wrappers[index].copy(wrapper); @@ -828,7 +814,7 @@ class {{=arrayWrapper}} { static freeArray(refObject) { {{? usePlainTypedArray}} {{/* For TypedArray, `.data` will be 'free()'-ed in parent struct. */}} - {{?? true}} + {{??}} let refObjectArray = refObject.data; refObjectArray.length = refObject.size; for (let index = 0; index < refObject.size; index++) { @@ -859,7 +845,7 @@ class {{=arrayWrapper}} { {{~ it.spec.constants :c}} {{? c.type === "string"}} Object.defineProperty({{=objectWrapper}}, "{{=c.name}}", {value: "{{=c.value}}", writable: false, enumerable: true, configurable: true}); -{{?? true}} +{{??}} Object.defineProperty({{=objectWrapper}}, "{{=c.name}}", {value: {{=c.value}}, writable: false, enumerable: true, configurable: true}); {{?}} {{~}} From dd1dbf87f657f6fd0efa8eaee7004a6bcfa4ccfb Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Tue, 31 Dec 2024 17:17:16 +0800 Subject: [PATCH 03/10] Fix format --- rosidl_gen/templates/message.dot | 37 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/rosidl_gen/templates/message.dot b/rosidl_gen/templates/message.dot index 10ef4320..2cdf1105 100644 --- a/rosidl_gen/templates/message.dot +++ b/rosidl_gen/templates/message.dot @@ -230,28 +230,28 @@ const deallocator = require('../../rosidl_gen/deallocator.js'); const translator = require('../../rosidl_gen/message_translator.js'); {{~ it.spec.fields :field}} -{{? shouldRequire(it.spec.baseType, field.type)}} -const {{=getWrapperNameByType(field.type)}} = require('../../generated/{{=getPackageNameByType(field.type)}}/{{=getModulePathByType(field.type, it.messageInfo)}}'); -{{?}} + {{? shouldRequire(it.spec.baseType, field.type)}} + const {{=getWrapperNameByType(field.type)}} = require('../../generated/{{=getPackageNameByType(field.type)}}/{{=getModulePathByType(field.type, it.messageInfo)}}'); + {{?}} {{~}} {{? it.spec.msgName === 'String'}} const {{=refObjectType}} = primitiveTypes.string; {{??}} const {{=refObjectType}} = StructType({ -{{~ it.spec.fields :field}} - {{? field.type.isPrimitiveType && !field.type.isArray}} - {{=field.name}}: primitiveTypes.{{=field.type.type}}, - {{?? field.type.isPrimitiveType && field.type.isArray && field.type.isFixedSizeArray}} - {{=field.name}}: ArrayType(primitiveTypes.{{=field.type.type}}, {{=field.type.arraySize}}), - {{?? !field.type.isPrimitiveType && field.type.isArray && field.type.isFixedSizeArray}} - {{=field.name}}: ArrayType({{=getWrapperNameByType(field.type)}}.refObjectType, {{=field.type.arraySize}}), - {{?? field.type.isArray}} - {{=field.name}}: {{=getWrapperNameByType(field.type)}}.refObjectArrayType, - {{?? true}} - {{=field.name}}: {{=getWrapperNameByType(field.type)}}.refObjectType, - {{?}} -{{~}} + {{~ it.spec.fields :field}} + {{? field.type.isPrimitiveType && !field.type.isArray}} + {{=field.name}}: primitiveTypes.{{=field.type.type}}, + {{?? field.type.isPrimitiveType && field.type.isArray && field.type.isFixedSizeArray}} + {{=field.name}}: ArrayType(primitiveTypes.{{=field.type.type}}, {{=field.type.arraySize}}), + {{?? !field.type.isPrimitiveType && field.type.isArray && field.type.isFixedSizeArray}} + {{=field.name}}: ArrayType({{=getWrapperNameByType(field.type)}}.refObjectType, {{=field.type.arraySize}}), + {{?? field.type.isArray}} + {{=field.name}}: {{=getWrapperNameByType(field.type)}}.refObjectArrayType, + {{??}} + {{=field.name}}: {{=getWrapperNameByType(field.type)}}.refObjectType, + {{?}} + {{~}} }); {{?}} @@ -259,7 +259,7 @@ const {{=refArrayType}} = ArrayType({{=refObjectType}}); const {{=refObjectArrayType}} = StructType({ {{? usePlainTypedArray}} data: ref.refType(ref.types.{{=currentTypedArrayElementType}}), -{{?? true}} +{{??}} data: {{=refArrayType}}, {{?}} size: ref.types.size_t, @@ -322,7 +322,6 @@ class {{=objectWrapper}} { this._willCheckConsistency = willCheckConsistency; this._wrapperFields = {}; this._refObject = new {{=refObjectType}}(); - {{~ it.spec.fields :field}} {{? field.type.isArray}} this._wrapperFields.{{=field.name}} = {{=getWrapperNameByType(field.type)}}.createArray(); @@ -708,7 +707,7 @@ class {{=arrayWrapper}} { {{? usePlainTypedArray}} const buffer = Buffer.from(new Uint8Array(this._wrappers.buffer)); this._refObject.data = buffer; - {{?? true}} + {{??}} this._refObject.data = this._refArray.buffer; {{?}} } From ee8b751968ef4faccbdff04f04f54892a8af7061 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Tue, 7 Jan 2025 18:09:32 +0800 Subject: [PATCH 04/10] Format the template --- rosidl_gen/templates/message.dot | 46 +++++++++++++++++--------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/rosidl_gen/templates/message.dot b/rosidl_gen/templates/message.dot index 2cdf1105..ff1a9e28 100644 --- a/rosidl_gen/templates/message.dot +++ b/rosidl_gen/templates/message.dot @@ -269,7 +269,7 @@ const {{=refObjectArrayType}} = StructType({ {{/* Define the wrapper class for the message. */}} class {{=objectWrapper}} { constructor(other, willCheckConsistency = false) { - this._initMembers(willCheckConsistency); + this._initialize(willCheckConsistency); this._setDefaults(); {{/* Construct `this` from `other`. */}} @@ -296,6 +296,7 @@ class {{=objectWrapper}} { this.freeze(); } + {{/* Set default values if the fields have. */}} _setDefaults() { {{~ it.spec.fields :field}} {{/* Set the flag of initialization. */}} @@ -318,7 +319,7 @@ class {{=objectWrapper}} { {{~}} } - _initMembers(willCheckConsistency) { + _initialize(willCheckConsistency) { this._willCheckConsistency = willCheckConsistency; this._wrapperFields = {}; this._refObject = new {{=refObjectType}}(); @@ -368,7 +369,7 @@ class {{=objectWrapper}} { return this._refObject.ref(); } - {{ /*Allocate the memory following the struct of the message*/ }} + {{ /*Assign values to the ref object. */ }} freeze(own = false, checkConsistency = false) { {{~ it.spec.fields :field}} {{? field.type.isPrimitiveType && !field.type.isArray}} @@ -409,6 +410,15 @@ class {{=objectWrapper}} { this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; } + {{?? field.type.isArray && field.type.isPrimitiveType && isTypedArrayType(field.type)}} + if (!own) { + this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); + this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; + } else { + this._wrapperFields.{{=field.name}}.fill({{=getTypedArrayName(field.type)}}.from([])); + this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); + this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; + } {{?? field.type.isArray && !field.type.isPrimitiveType && field.type.isFixedSizeArray}} for (let i = 0; i < {{=field.type.arraySize}}; i++) { if (this._wrapperFields.{{=field.name}}.data[i]) { @@ -416,16 +426,9 @@ class {{=objectWrapper}} { this._refObject.{{=field.name}}[i] = this._wrapperFields.{{=field.name}}.data[i].refObject; } } - {{?? !field.type.isPrimitiveType || field.type.isArray}} + {{?? field.type.isArray || !field.type.isPrimitiveType}} this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; - {{? field.type.isArray && field.type.isPrimitiveType}} - if (own) { - this._wrapperFields.{{=field.name}}.fill({{=getTypedArrayName(field.type)}}.from([])); - this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); - this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; - } - {{?}} {{?? field.type.type === 'string' && it.spec.msgName !== 'String'}} if (own) { this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); @@ -470,7 +473,7 @@ class {{=objectWrapper}} { for (let i = 0; i < {{=field.type.arraySize}}; i++) { this._wrapperFields.{{=field.name}}.data[i].copyRefObject(refObject.{{=field.name}}[i]); } - {{?? !field.type.isPrimitiveType || field.type.isArray}} + {{?? field.type.isArray || !field.type.isPrimitiveType}} this._wrapperFields.{{=field.name}}.copyRefObject(refObject.{{=field.name}}); {{?? field.type.type === 'string' && it.spec.msgName !== 'String'}} this._wrapperFields.{{=field.name}}.data = refObject.{{=field.name}}.data; @@ -565,6 +568,7 @@ class {{=objectWrapper}} { if (value.length !== {{=field.type.arraySize}}) { throw new RangeError('The length of the array must be {{=field.type.arraySize}}.'); } + {{?}} {{?field.type.isArray && field.type.isUpperBound}} if (value.length > {{=field.type.arraySize}}) { @@ -660,7 +664,7 @@ class {{=arrayWrapper}} { fill(values) { {{? usePlainTypedArray}} if (Array.isArray(values)) { - {{/* Convert JavaScript array. */}} + {{/* Convert to TypedArray. */}} this._wrappers = new {{=currentTypedArray}}(values); } else { this._wrappers = values; @@ -840,14 +844,14 @@ class {{=arrayWrapper}} { } {{? it.spec.constants != undefined && it.spec.constants.length}} -{{/* Define constants ({{=it.spec.constants.length}} in total). */}} -{{~ it.spec.constants :c}} -{{? c.type === "string"}} -Object.defineProperty({{=objectWrapper}}, "{{=c.name}}", {value: "{{=c.value}}", writable: false, enumerable: true, configurable: true}); -{{??}} -Object.defineProperty({{=objectWrapper}}, "{{=c.name}}", {value: {{=c.value}}, writable: false, enumerable: true, configurable: true}); -{{?}} -{{~}} + {{/* Define constants ({{=it.spec.constants.length}} in total). */}} + {{~ it.spec.constants :c}} + {{? c.type === "string"}} + Object.defineProperty({{=objectWrapper}}, "{{=c.name}}", {value: "{{=c.value}}", writable: false, enumerable: true, configurable: true}); + {{??}} + Object.defineProperty({{=objectWrapper}}, "{{=c.name}}", {value: {{=c.value}}, writable: false, enumerable: true, configurable: true}); + {{?}} + {{~}} {{?}} module.exports = {{=objectWrapper}}; From 491aa540548c8386d7fa48ad4d52336268ef62b1 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Wed, 8 Jan 2025 14:17:02 +0800 Subject: [PATCH 05/10] Remove consistency checking --- lib/client.js | 1 - lib/node.js | 7 --- lib/publisher.js | 1 - rosidl_gen/templates/message.dot | 41 ++------------- test/test-compound-msg-type-check.js | 5 -- test/test-security-related.js | 78 ---------------------------- 6 files changed, 5 insertions(+), 128 deletions(-) diff --git a/lib/client.js b/lib/client.js index 4d8f0d8a..b29c22a9 100644 --- a/lib/client.js +++ b/lib/client.js @@ -58,7 +58,6 @@ class Client extends Entity { request instanceof this._typeClass.Request ? request : new this._typeClass.Request(request); - requestToSend._willCheckConsistency = this._options.willCheckConsistency; let rawRequest = requestToSend.serialize(); let sequenceNumber = rclnodejs.sendRequest(this._handle, rawRequest); diff --git a/lib/node.js b/lib/node.js index 89213d51..fdc7da43 100644 --- a/lib/node.js +++ b/lib/node.js @@ -502,10 +502,6 @@ class Node extends rclnodejs.ShadowNode { options = Object.assign(options, { isRaw: false }); } - if (options.willCheckConsistency === undefined) { - options = Object.assign(options, { willCheckConsistency: false }); - } - return options; } @@ -592,7 +588,6 @@ class Node extends rclnodejs.ShadowNode { * @param {object} options - The options argument used to parameterize the publisher. * @param {boolean} options.enableTypedArray - The topic will use TypedArray if necessary, default: true. * @param {QoS} options.qos - ROS Middleware "quality of service" settings for the publisher, default: QoS.profileDefault. - * @param {boolean} options.willCheckConsistency - Pulisher will check the consistancy of the message to be sent, default: false. * @return {Publisher} - An instance of Publisher. */ createPublisher(typeClass, topic, options) { @@ -695,7 +690,6 @@ class Node extends rclnodejs.ShadowNode { * @param {object} options - The options argument used to parameterize the client. * @param {boolean} options.enableTypedArray - The response will use TypedArray if necessary, default: true. * @param {QoS} options.qos - ROS Middleware "quality of service" settings for the client, default: QoS.profileDefault. - * @param {boolean} options.willCheckConsistency - Client will check the consistancy of the message to be sent, default: false. * @return {Client} - An instance of Client. */ createClient(typeClass, serviceName, options) { @@ -1696,7 +1690,6 @@ Node.getDefaultOptions = function () { isRaw: false, qos: QoS.profileDefault, contentFilter: undefined, - willCheckConsistency: false, }; }; diff --git a/lib/publisher.js b/lib/publisher.js index fd42c68d..4550690c 100644 --- a/lib/publisher.js +++ b/lib/publisher.js @@ -53,7 +53,6 @@ class Publisher extends Entity { message instanceof this._typeClass ? message : new this._typeClass(message); - messageToSend._willCheckConsistency = this._options.willCheckConsistency; let rawMessage = messageToSend.serialize(); rclnodejs.publish(this._handle, rawMessage); } diff --git a/rosidl_gen/templates/message.dot b/rosidl_gen/templates/message.dot index ff1a9e28..7b633b3d 100644 --- a/rosidl_gen/templates/message.dot +++ b/rosidl_gen/templates/message.dot @@ -268,17 +268,14 @@ const {{=refObjectArrayType}} = StructType({ {{/* Define the wrapper class for the message. */}} class {{=objectWrapper}} { - constructor(other, willCheckConsistency = false) { - this._initialize(willCheckConsistency); + constructor(other) { + this._initialize(); this._setDefaults(); {{/* Construct `this` from `other`. */}} if (typeof other === 'object' && other._refObject) { this._refObject = new {{=refObjectType}}(other._refObject.toObject()); {{~ it.spec.fields :field}} - {{? field.type.isPrimitiveType && !field.type.isArray}} - this._{{=field.name}}Intialized = true; - {{?}} {{? field.type.isArray}} this._wrapperFields.{{=field.name}} = {{=getWrapperNameByType(field.type)}}.createArray(); this._wrapperFields.{{=field.name}}.copy(other._wrapperFields.{{=field.name}}); @@ -300,10 +297,7 @@ class {{=objectWrapper}} { _setDefaults() { {{~ it.spec.fields :field}} {{/* Set the flag of initialization. */}} - {{? it.spec.isEmpty}} - this._{{=field.name}}Intialized = true; - {{?? field.type.isPrimitiveType && !field.type.isArray && field.default_value}} - this._{{=field.name}}Intialized = true; + {{? field.type.isPrimitiveType && !field.type.isArray && field.default_value}} {{? field.type.type === 'string' || field.type.type === 'wstring'}} this._refObject.{{=field.name}} = "{{=field.default_value.replace(/"/g, '\\"')}}"; {{??}} @@ -313,14 +307,11 @@ class {{=objectWrapper}} { this._{{=field.name}}Array = {{=JSON.stringify(field.default_value)}}; {{?? field.type.isPrimitiveType && isTypedArrayType(field.type) && field.default_value}} this._wrapperFields.{{=field.name}}.fill({{=getTypedArrayName(field.type)}}.from({{=JSON.stringify(field.default_value)}})); - {{??}} - this._{{=field.name}}Intialized = false; {{?}} {{~}} } - _initialize(willCheckConsistency) { - this._willCheckConsistency = willCheckConsistency; + _initialize() { this._wrapperFields = {}; this._refObject = new {{=refObjectType}}(); {{~ it.spec.fields :field}} @@ -371,14 +362,6 @@ class {{=objectWrapper}} { {{ /*Assign values to the ref object. */ }} freeze(own = false, checkConsistency = false) { - {{~ it.spec.fields :field}} - {{? field.type.isPrimitiveType && !field.type.isArray}} - if (checkConsistency && !this._{{=field.name}}Intialized) { - throw new TypeError('Invalid argument: {{=field.name}} in {{=it.spec.msgName}}'); - } - {{?}} - {{~}} - {{~ it.spec.fields :field}} {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type) && field.type.isFixedSizeArray}} {{? field.type.type === 'string'}} @@ -443,14 +426,12 @@ class {{=objectWrapper}} { } serialize() { - this.freeze(/*own=*/false, this._willCheckConsistency); + this.freeze(/*own=*/false); return this._refObject.ref(); } deserialize(refObject) { {{~ it.spec.fields :field}} - this._{{=field.name}}Intialized = true; - {{? field.type.isArray && field.type.isPrimitiveType && field.type.isFixedSizeArray && isTypedArrayType(field.type)}} this._wrapperFields.{{=field.name}}.fill(refObject.{{=field.name}}.toArray()); {{?? field.type.isArray && field.type.isPrimitiveType && field.type.isFixedSizeArray && !isTypedArrayType(field.type)}} @@ -547,23 +528,13 @@ class {{=objectWrapper}} { {{?? !field.type.isPrimitiveType && !field.type.isArray}} return this._wrapperFields.{{=field.name}}; {{?? !field.type.isArray && field.type.type === 'string' && it.spec.msgName !== 'String'}} - if (!this._{{=field.name}}Intialized) { - return undefined; - } return this._wrapperFields.{{=field.name}}.data; {{??}} - if (!this._{{=field.name}}Intialized) { - return undefined; - } return this._refObject.{{=field.name}}; {{?}} } set {{=field.name}}(value) { - {{? field.type.isPrimitiveType && !field.type.isArray}} - this._{{=field.name}}Intialized = true; - {{?}} - {{?field.type.isArray && field.type.isFixedSizeArray}} if (value.length !== {{=field.type.arraySize}}) { throw new RangeError('The length of the array must be {{=field.type.arraySize}}.'); @@ -604,7 +575,6 @@ class {{=objectWrapper}} { this._refObject = new {{=refObjectType}}(refObject.toObject()); {{~ it.spec.fields :field}} - this._{{=field.name}}Intialized = true; {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} refObject.{{=field.name}}.data.length = refObject.{{=field.name}}.size; for (let index = 0; index < refObject.{{=field.name}}.size; index++) { @@ -628,7 +598,6 @@ class {{=objectWrapper}} { this._refObject = new {{=refObjectType}}(other._refObject.toObject()); {{~ it.spec.fields :field}} - this._{{=field.name}}Intialized = true; {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} this._{{=field.name}}Array = other._{{=field.name}}Array.slice(); {{?? !field.type.isPrimitiveType || field.type.isArray || (field.type.type === 'string' && it.spec.msgName !== 'String')}} diff --git a/test/test-compound-msg-type-check.js b/test/test-compound-msg-type-check.js index 721408dc..6c7a970c 100644 --- a/test/test-compound-msg-type-check.js +++ b/test/test-compound-msg-type-check.js @@ -34,10 +34,6 @@ describe('Compound types', function () { let msg = new msgColorRGBA(); assert.ok('r' in msg && 'g' in msg && 'b' in msg && 'a' in msg); - assert.deepStrictEqual(typeof msg.r, 'undefined'); - assert.deepStrictEqual(typeof msg.g, 'undefined'); - assert.deepStrictEqual(typeof msg.b, 'undefined'); - assert.deepStrictEqual(typeof msg.a, 'undefined'); }); it('Array', function () { @@ -60,7 +56,6 @@ describe('Compound types', function () { assert.ok('frame_id' in header); assert.deepStrictEqual(typeof header.stamp, 'object'); - assert.deepStrictEqual(typeof header.frame_id, 'undefined'); }); it('Complex object', function () { diff --git a/test/test-security-related.js b/test/test-security-related.js index f4345c84..319238d4 100644 --- a/test/test-security-related.js +++ b/test/test-security-related.js @@ -213,84 +213,6 @@ describe('Fuzzing API calls testing', function () { node.destroy(); }); - it('Inconsistent message type for subscription', function () { - var node = rclnodejs.createNode('node1', '/inconsistent'); - const RclString = 'std_msgs/msg/String'; - - var publisher = node.createPublisher(RclString, 'chatter7', { - willCheckConsistency: true, - }); - assertThrowsError( - () => { - publisher.publish({ a: 1 }); - }, - TypeError, - 'Invalid argument', - `Type should be ${RclString}` - ); - - const String = rclnodejs.require(RclString); - const str = new String(); - str.a = 1; - assertThrowsError( - () => { - publisher.publish(str); - }, - TypeError, - 'Invalid argument', - `Type should be ${RclString}` - ); - - rclnodejs.spin(node); - node.destroy(); - }); - - it('Inconsistent request data for service', function () { - var node = rclnodejs.createNode('node2', '/inconsistent'); - const AddTwoInts = 'example_interfaces/srv/AddTwoInts'; - - var client = node.createClient(AddTwoInts, 'add_two_ints', { - willCheckConsistency: true, - }); - var service = node.createService( - AddTwoInts, - 'add_two_ints', - (request, response) => { - assert.throws( - () => { - request.b; - }, - Error, - 'This should never be reached.' - ); - } - ); - - assertThrowsError( - () => { - client.sendRequest({ a: 1 }, (response) => {}); - }, - TypeError, - 'Invalid argument', - 'request.b does not exist' - ); - - const Request = rclnodejs.require(AddTwoInts).Request; - const req = new Request(); - req.a = 1; - assertThrowsError( - () => { - client.sendRequest(req, (response) => {}); - }, - TypeError, - 'Invalid argument', - 'request.b does not exist' - ); - - rclnodejs.spin(node); - node.destroy(); - }); - it('resources will be freed by shutdown', function () { var node = rclnodejs.createNode('node1', '/unhandled'); const RclString = 'std_msgs/msg/String'; From f97473a0a6621a124516cc70b51ef8f65f7cadf8 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Wed, 8 Jan 2025 14:52:54 +0800 Subject: [PATCH 06/10] Pump to 0.4.0 --- rosidl_gen/generator.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rosidl_gen/generator.json b/rosidl_gen/generator.json index e0b58759..7664cec9 100644 --- a/rosidl_gen/generator.json +++ b/rosidl_gen/generator.json @@ -1,6 +1,6 @@ { "name": "rosidl-generator", - "version": "0.3.10", + "version": "0.4.0", "description": "Generate JavaScript object from ROS IDL(.msg) files", "main": "index.js", "authors": [ From 359eb6800a6085183e48fb73fd003d4a5ed3a650 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Mon, 13 Jan 2025 18:02:00 +0800 Subject: [PATCH 07/10] Cleanup --- rosidl_gen/idl_generator.js | 2 +- rosidl_gen/templates/message.dot | 33 +++++++++++++++----------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/rosidl_gen/idl_generator.js b/rosidl_gen/idl_generator.js index 598721ee..8803441b 100644 --- a/rosidl_gen/idl_generator.js +++ b/rosidl_gen/idl_generator.js @@ -42,7 +42,7 @@ function removeEmptyLines(str) { */ async function writeGeneratedCode(dir, fileName, code) { if (fileName.endsWith('.js')) { - code = await prettier.format(code, { singleQuote: true, parser: 'babel' }); + code = await prettier.format(code, { parser: 'babel' }); } await fse.mkdirs(dir); await fse.writeFile(path.join(dir, fileName), code); diff --git a/rosidl_gen/templates/message.dot b/rosidl_gen/templates/message.dot index 7b633b3d..ccee24a3 100644 --- a/rosidl_gen/templates/message.dot +++ b/rosidl_gen/templates/message.dot @@ -69,7 +69,7 @@ function getPrimitiveNameByType(type) { function getTypedArrayName(type) { const t = type.type.toLowerCase(); - let typedArrayName; + let typedArrayName = null; switch (t) { case 'byte': @@ -257,11 +257,11 @@ const {{=refObjectType}} = StructType({ const {{=refArrayType}} = ArrayType({{=refObjectType}}); const {{=refObjectArrayType}} = StructType({ -{{? usePlainTypedArray}} + {{? usePlainTypedArray}} data: ref.refType(ref.types.{{=currentTypedArrayElementType}}), -{{??}} + {{??}} data: {{=refArrayType}}, -{{?}} + {{?}} size: ref.types.size_t, capacity: ref.types.size_t }); @@ -296,7 +296,6 @@ class {{=objectWrapper}} { {{/* Set default values if the fields have. */}} _setDefaults() { {{~ it.spec.fields :field}} - {{/* Set the flag of initialization. */}} {{? field.type.isPrimitiveType && !field.type.isArray && field.default_value}} {{? field.type.type === 'string' || field.type.type === 'wstring'}} this._refObject.{{=field.name}} = "{{=field.default_value.replace(/"/g, '\\"')}}"; @@ -360,8 +359,8 @@ class {{=objectWrapper}} { return this._refObject.ref(); } - {{ /*Assign values to the ref object. */ }} - freeze(own = false, checkConsistency = false) { + {{ /*Assign values to the ref object wrapped by `this`. */ }} + freeze(own = false) { {{~ it.spec.fields :field}} {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type) && field.type.isFixedSizeArray}} {{? field.type.type === 'string'}} @@ -386,35 +385,35 @@ class {{=objectWrapper}} { {{?? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} if (!own) { this._wrapperFields.{{=field.name}}.fill(this._{{=field.name}}Array); - this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); + this._wrapperFields.{{=field.name}}.freeze(own); this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; } else { this._wrapperFields.{{=field.name}}.fill([]); - this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); + this._wrapperFields.{{=field.name}}.freeze(own); this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; } {{?? field.type.isArray && field.type.isPrimitiveType && isTypedArrayType(field.type)}} if (!own) { - this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); + this._wrapperFields.{{=field.name}}.freeze(own); this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; } else { this._wrapperFields.{{=field.name}}.fill({{=getTypedArrayName(field.type)}}.from([])); - this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); + this._wrapperFields.{{=field.name}}.freeze(own); this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; } {{?? field.type.isArray && !field.type.isPrimitiveType && field.type.isFixedSizeArray}} for (let i = 0; i < {{=field.type.arraySize}}; i++) { if (this._wrapperFields.{{=field.name}}.data[i]) { - this._wrapperFields.{{=field.name}}.data[i].freeze(own, checkConsistency); + this._wrapperFields.{{=field.name}}.data[i].freeze(own); this._refObject.{{=field.name}}[i] = this._wrapperFields.{{=field.name}}.data[i].refObject; } } {{?? field.type.isArray || !field.type.isPrimitiveType}} - this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); + this._wrapperFields.{{=field.name}}.freeze(own); this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; {{?? field.type.type === 'string' && it.spec.msgName !== 'String'}} if (own) { - this._wrapperFields.{{=field.name}}.freeze(own, checkConsistency); + this._wrapperFields.{{=field.name}}.freeze(own); } this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; {{?? it.spec.msgName === 'String'}} @@ -439,8 +438,8 @@ class {{=objectWrapper}} { for (let index = 0; index < {{=field.type.arraySize}}; index++) { this._{{=field.name}}Array[index] = refObject.{{=field.name}}[index].data; } - {{/* For non-typed array like int64/uint64/bool. */}} {{??}} + {{/* For non-typed array like int64/uint64/bool. */}} this._{{=field.name}}Array = refObject.{{=field.name}}.toArray(); {{?}} {{?? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} @@ -701,7 +700,6 @@ class {{=arrayWrapper}} { set size(value) { if (typeof value != 'number') { throw new TypeError('Invalid argument: should provide a number to {{=arrayWrapper}}.size setter'); - return; } return this._resize(value); } @@ -724,7 +722,6 @@ class {{=arrayWrapper}} { _resize(size) { if (size < 0) { throw new RangeError('Invalid argument: should provide a positive number'); - return; } {{? usePlainTypedArray}} this._refArray = undefined; @@ -776,7 +773,7 @@ class {{=arrayWrapper}} { {{? usePlainTypedArray}} this._wrappers = other._wrappers.slice(); {{??}} - {{/* Array deep copy. */}} + {{/* Deep copy for the type of Array. */}} other._wrappers.forEach((wrapper, index) => { this._wrappers[index].copy(wrapper); }); From e674a83c6281004434f81033798a6de3168147dc Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Tue, 14 Jan 2025 11:21:43 +0800 Subject: [PATCH 08/10] Correct comments --- rosidl_gen/templates/message.dot | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rosidl_gen/templates/message.dot b/rosidl_gen/templates/message.dot index ccee24a3..03fccfb7 100644 --- a/rosidl_gen/templates/message.dot +++ b/rosidl_gen/templates/message.dot @@ -293,7 +293,7 @@ class {{=objectWrapper}} { this.freeze(); } - {{/* Set default values if the fields have. */}} + {{/* Set default values if the fields of the message have. */}} _setDefaults() { {{~ it.spec.fields :field}} {{? field.type.isPrimitiveType && !field.type.isArray && field.default_value}} @@ -376,8 +376,8 @@ class {{=objectWrapper}} { } } } - {{/* For non-typed array like int64/uint64/bool. */}} {{??}} + {{/* For non-typed array like int64/uint64/bool. */}} this._refObject.{{=field.name}} = this._{{=field.name}}Array; {{?}} {{?? field.type.isArray && field.type.isPrimitiveType && isTypedArrayType(field.type) && field.type.isFixedSizeArray}} @@ -661,9 +661,8 @@ class {{=arrayWrapper}} { {{/* Put all data currently stored in `this._wrappers` into `this._refObject`. */}} freeze(own) { - {{? usePlainTypedArray}} {{/* When it's a TypedArray: no need to copy to `this._refArray`. */}} - {{??}} + {{? !usePlainTypedArray}} this._wrappers.forEach((wrapper, index) => { wrapper.freeze(own); this._refArray[index] = wrapper.refObject; From b217cf5333644fe044c9ff0bb72b6721c12b08f5 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Tue, 14 Jan 2025 13:33:21 +0800 Subject: [PATCH 09/10] Revise comments --- rosidl_gen/templates/message.dot | 40 +++++++++++++++----------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/rosidl_gen/templates/message.dot b/rosidl_gen/templates/message.dot index 03fccfb7..69045f15 100644 --- a/rosidl_gen/templates/message.dot +++ b/rosidl_gen/templates/message.dot @@ -157,7 +157,7 @@ function isTypedArrayType(type) { return typedArrayType.indexOf(type.type.toLowerCase()) !== -1; } -const usePlainTypedArray = isTypedArrayType(it.spec.baseType); +const willUseTypedArray = isTypedArrayType(it.spec.baseType); const currentTypedArray = getTypedArrayName(it.spec.baseType); const currentTypedArrayElementType = getTypedArrayElementName(it.spec.baseType); @@ -219,7 +219,7 @@ function extractMemberNames(fields) { } }} -{{? usePlainTypedArray}} +{{? willUseTypedArray}} const rclnodejs = require('bindings')('rclnodejs'); {{?}} const ref = require('@rclnodejs/ref-napi'); @@ -257,7 +257,7 @@ const {{=refObjectType}} = StructType({ const {{=refArrayType}} = ArrayType({{=refObjectType}}); const {{=refObjectArrayType}} = StructType({ - {{? usePlainTypedArray}} + {{? willUseTypedArray}} data: ref.refType(ref.types.{{=currentTypedArrayElementType}}), {{??}} data: {{=refArrayType}}, @@ -377,7 +377,7 @@ class {{=objectWrapper}} { } } {{??}} - {{/* For non-typed array like int64/uint64/bool. */}} + {{/* For non-TypedArray like int64/uint64/bool. */}} this._refObject.{{=field.name}} = this._{{=field.name}}Array; {{?}} {{?? field.type.isArray && field.type.isPrimitiveType && isTypedArrayType(field.type) && field.type.isFixedSizeArray}} @@ -439,7 +439,7 @@ class {{=objectWrapper}} { this._{{=field.name}}Array[index] = refObject.{{=field.name}}[index].data; } {{??}} - {{/* For non-typed array like int64/uint64/bool. */}} + {{/* For non-TypedArray like int64/uint64/bool. */}} this._{{=field.name}}Array = refObject.{{=field.name}}.toArray(); {{?}} {{?? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} @@ -472,9 +472,8 @@ class {{=objectWrapper}} { {{? field.type.isArray && !field.type.isFixedSizeArray}} if (refObject.{{=field.name}}.size != 0) { {{=getWrapperNameByType(field.type)}}.ArrayType.freeArray(refObject.{{=field.name}}); - if ({{=getWrapperNameByType(field.type)}}.ArrayType.useTypedArray) { - {{/* Do nothing, the v8 will take the ownership of the ArrayBuffer used by the typed array. */}} - } else { + {{/* We don't need to free the memory for TypedArray objects, because v8 takes the ownership of it. */}} + if (!{{=getWrapperNameByType(field.type)}}.ArrayType.useTypedArray) { deallocator.freeStructMember(refObject.{{=field.name}}, {{=getWrapperNameByType(field.type)}}.refObjectArrayType, 'data'); } } @@ -630,7 +629,7 @@ class {{=arrayWrapper}} { } fill(values) { - {{? usePlainTypedArray}} + {{? willUseTypedArray}} if (Array.isArray(values)) { {{/* Convert to TypedArray. */}} this._wrappers = new {{=currentTypedArray}}(values); @@ -662,7 +661,7 @@ class {{=arrayWrapper}} { {{/* Put all data currently stored in `this._wrappers` into `this._refObject`. */}} freeze(own) { {{/* When it's a TypedArray: no need to copy to `this._refArray`. */}} - {{? !usePlainTypedArray}} + {{? !willUseTypedArray}} this._wrappers.forEach((wrapper, index) => { wrapper.freeze(own); this._refArray[index] = wrapper.refObject; @@ -675,7 +674,7 @@ class {{=arrayWrapper}} { if (this._refObject.capacity === 0) { this._refObject.data = null } else { - {{? usePlainTypedArray}} + {{? willUseTypedArray}} const buffer = Buffer.from(new Uint8Array(this._wrappers.buffer)); this._refObject.data = buffer; {{??}} @@ -722,7 +721,7 @@ class {{=arrayWrapper}} { if (size < 0) { throw new RangeError('Invalid argument: should provide a positive number'); } - {{? usePlainTypedArray}} + {{? willUseTypedArray}} this._refArray = undefined; {{??}} this._refArray = new {{=refArrayType}}(size); @@ -732,7 +731,7 @@ class {{=arrayWrapper}} { this._refObject.size = size; this._refObject.capacity = size; - {{? usePlainTypedArray}} + {{? willUseTypedArray}} this._wrappers = new {{=currentTypedArray}}(size); {{??}} this._wrappers = new Array(); @@ -746,9 +745,9 @@ class {{=arrayWrapper}} { copyRefObject(refObject) { this._refObject = refObject; - {{? usePlainTypedArray}} + {{? willUseTypedArray}} const byteLen = refObject.size * ref.types.{{=currentTypedArrayElementType}}.size; - {{/* An ArrayBuffer object doesn't hold the ownership of memory block starting from address. */}} + {{/* An ArrayBuffer object doesn't hold the ownership of memory block starting from address for TypedArray. */}} const arrayBuffer = refObject.data.length !== 0 ? rclnodejs.createArrayBufferFromAddress(refObject.data.hexAddress(), byteLen) : Buffer.alloc(0); @@ -769,10 +768,10 @@ class {{=arrayWrapper}} { } this._resize(other.size); - {{? usePlainTypedArray}} + {{? willUseTypedArray}} this._wrappers = other._wrappers.slice(); {{??}} - {{/* Deep copy for the type of Array. */}} + {{/* Deep copy for non-TypedArray. */}} other._wrappers.forEach((wrapper, index) => { this._wrappers[index].copy(wrapper); }); @@ -780,9 +779,8 @@ class {{=arrayWrapper}} { } static freeArray(refObject) { - {{? usePlainTypedArray}} - {{/* For TypedArray, `.data` will be 'free()'-ed in parent struct. */}} - {{??}} + {{/* We don't need to free the memory for TypedArray objects, because v8 takes the ownership of it. */}} + {{? !willUseTypedArray}} let refObjectArray = refObject.data; refObjectArray.length = refObject.size; for (let index = 0; index < refObject.size; index++) { @@ -800,7 +798,7 @@ class {{=arrayWrapper}} { } static get useTypedArray() { - return {{=usePlainTypedArray}}; + return {{=willUseTypedArray}}; } get classType() { From 0ea44973c27673496e1ae5274a4b8f09a9d66d74 Mon Sep 17 00:00:00 2001 From: Minggang Wang Date: Tue, 14 Jan 2025 17:23:54 +0800 Subject: [PATCH 10/10] Remove default parameter for freeze() --- rosidl_gen/templates/message.dot | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/rosidl_gen/templates/message.dot b/rosidl_gen/templates/message.dot index 69045f15..c43393f2 100644 --- a/rosidl_gen/templates/message.dot +++ b/rosidl_gen/templates/message.dot @@ -290,7 +290,7 @@ class {{=objectWrapper}} { {{/* Try to construct the message from a plan object of JavaScript. */}} translator.constructFromPlanObject(this, other); } - this.freeze(); + this.freeze(/*own=*/false); } {{/* Set default values if the fields of the message have. */}} @@ -360,7 +360,7 @@ class {{=objectWrapper}} { } {{ /*Assign values to the ref object wrapped by `this`. */ }} - freeze(own = false) { + freeze(own) { {{~ it.spec.fields :field}} {{? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type) && field.type.isFixedSizeArray}} {{? field.type.type === 'string'}} @@ -383,24 +383,19 @@ class {{=objectWrapper}} { {{?? field.type.isArray && field.type.isPrimitiveType && isTypedArrayType(field.type) && field.type.isFixedSizeArray}} this._refObject.{{=field.name}} = Array.from(this._wrapperFields.{{=field.name}}.data); {{?? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} - if (!own) { - this._wrapperFields.{{=field.name}}.fill(this._{{=field.name}}Array); - this._wrapperFields.{{=field.name}}.freeze(own); - this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; - } else { + if (own) { this._wrapperFields.{{=field.name}}.fill([]); - this._wrapperFields.{{=field.name}}.freeze(own); - this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; + } else { + this._wrapperFields.{{=field.name}}.fill(this._{{=field.name}}Array); } + this._wrapperFields.{{=field.name}}.freeze(own); + this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; {{?? field.type.isArray && field.type.isPrimitiveType && isTypedArrayType(field.type)}} - if (!own) { - this._wrapperFields.{{=field.name}}.freeze(own); - this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; - } else { + if (own) { this._wrapperFields.{{=field.name}}.fill({{=getTypedArrayName(field.type)}}.from([])); - this._wrapperFields.{{=field.name}}.freeze(own); - this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; } + this._wrapperFields.{{=field.name}}.freeze(own); + this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; {{?? field.type.isArray && !field.type.isPrimitiveType && field.type.isFixedSizeArray}} for (let i = 0; i < {{=field.type.arraySize}}; i++) { if (this._wrapperFields.{{=field.name}}.data[i]) { @@ -409,6 +404,11 @@ class {{=objectWrapper}} { } } {{?? field.type.isArray || !field.type.isPrimitiveType}} + {{? field.type.isArray}} + if (own) { + this._wrapperFields.{{=field.name}}.fill([]); + } + {{?}} this._wrapperFields.{{=field.name}}.freeze(own); this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; {{?? field.type.type === 'string' && it.spec.msgName !== 'String'}}