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/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/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": [ diff --git a/rosidl_gen/idl_generator.js b/rosidl_gen/idl_generator.js index f09674f2..8803441b 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, { 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 d9160eff..c43393f2 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') { @@ -69,7 +69,7 @@ function getPrimitiveNameByType(type) { function getTypedArrayName(type) { const t = type.type.toLowerCase(); - let typedArrayName; + let typedArrayName = null; switch (t) { case 'byte': @@ -108,7 +108,6 @@ function getTypedArrayName(type) { default: typedArrayName = ''; } - return typedArrayName; } @@ -158,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); @@ -220,7 +219,7 @@ function extractMemberNames(fields) { } }} -{{? usePlainTypedArray}} +{{? willUseTypedArray}} const rclnodejs = require('bindings')('rclnodejs'); {{?}} const ref = require('@rclnodejs/ref-napi'); @@ -231,116 +230,105 @@ 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, + {{?}} + {{~}} }); {{?}} const {{=refArrayType}} = ArrayType({{=refObjectType}}); const {{=refObjectArrayType}} = StructType({ -{{? usePlainTypedArray}} + {{? willUseTypedArray}} data: ref.refType(ref.types.{{=currentTypedArrayElementType}}), -{{?? true}} + {{??}} data: {{=refArrayType}}, -{{?}} + {{?}} size: ref.types.size_t, 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 = []; - {{?}} - {{~}} + 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}}); - {{? 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.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. */}} translator.constructFromPlanObject(this, other); - } else { - this._initMembers(); } - this.freeze(); + this.freeze(/*own=*/false); } - _initMembers() { - this._refObject = new {{=refObjectType}}(); + {{/* Set default values if the fields of the message have. */}} + _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; - {{?}} - {{?}} + {{? 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, '\\"')}}"; + {{??}} + 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)}})); + {{?}} + {{~}} + } - {{? 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); - {{?}} - {{?}} + _initialize() { + 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); + {{?}} {{~}} } @@ -367,102 +355,93 @@ class {{=objectWrapper}} { } toRawROS() { - this.freeze(true); + this.freeze(/*own=*/true); return this._refObject.ref(); } - 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}}'); - } - {{?}} - {{~}} - + {{ /*Assign values to the ref object wrapped by `this`. */ }} + freeze(own) { {{~ 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++) { + {{? 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-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}} + this._refObject.{{=field.name}} = Array.from(this._wrapperFields.{{=field.name}}.data); + {{?? field.type.isArray && field.type.isPrimitiveType && !isTypedArrayType(field.type)}} if (own) { - primitiveTypes.initString(this._refObject.{{=field.name}}[i].ref(), own); + this._wrapperFields.{{=field.name}}.fill([]); } 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._{{=field.name}}Array); } - } - // 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._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); + {{?? field.type.isArray && field.type.isPrimitiveType && isTypedArrayType(field.type)}} + 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; - } - {{?? 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 && 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); + this._refObject.{{=field.name}}[i] = this._wrapperFields.{{=field.name}}.data[i].refObject; + } } - } - {{?? !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); + {{?? 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'}} - 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); - } - {{?}} + {{?? field.type.type === 'string' && it.spec.msgName !== 'String'}} + if (own) { + this._wrapperFields.{{=field.name}}.freeze(own); + } + this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject; + {{?? it.spec.msgName === 'String'}} + if (own) { + primitiveTypes.initString(this._refObject.ref(), own); + } + {{?}} {{~}} } serialize() { - this.freeze(/*own=*/false, this._willCheckConsistency); + this.freeze(/*own=*/false); return this._refObject.ref(); } 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-TypedArray 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++) { @@ -474,7 +453,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; @@ -493,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'); } } @@ -548,27 +526,18 @@ 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; - {{?? true}} - 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}}.'); } + {{?}} {{?field.type.isArray && field.type.isUpperBound}} if (value.length > {{=field.type.arraySize}}) { @@ -590,11 +559,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; {{?}} } @@ -604,26 +573,22 @@ 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}}); - {{?}} + {{? 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}}); + {{?}} {{~}} } @@ -631,15 +596,11 @@ 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}}); - {{?}} + {{? 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}}); + {{?}} {{~}} } @@ -657,7 +618,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); @@ -668,15 +629,15 @@ class {{=arrayWrapper}} { } fill(values) { - {{? usePlainTypedArray}} + {{? willUseTypedArray}} if (Array.isArray(values)) { - // Convert JavaScript array + {{/* Convert to TypedArray. */}} 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) { @@ -684,7 +645,7 @@ class {{=arrayWrapper}} { wrapper.data = values[i]; this._wrappers[i] = wrapper; } - {{?? true}} + {{??}} const length = values.length; this._resize(length); values.forEach((value, index) => { @@ -697,11 +658,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` - {{?? true}} + {{/* When it's a TypedArray: no need to copy to `this._refArray`. */}} + {{? !willUseTypedArray}} this._wrappers.forEach((wrapper, index) => { wrapper.freeze(own); this._refArray[index] = wrapper.refObject; @@ -714,12 +674,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; - {{?}} + {{? willUseTypedArray}} + const buffer = Buffer.from(new Uint8Array(this._wrappers.buffer)); + this._refObject.data = buffer; + {{??}} + this._refObject.data = this._refArray.buffer; + {{?}} } } @@ -738,7 +698,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); } @@ -761,11 +720,10 @@ class {{=arrayWrapper}} { _resize(size) { if (size < 0) { throw new RangeError('Invalid argument: should provide a positive number'); - return; } - {{? usePlainTypedArray}} + {{? willUseTypedArray}} this._refArray = undefined; - {{?? true}} + {{??}} this._refArray = new {{=refArrayType}}(size); {{?}} @@ -773,9 +731,9 @@ class {{=arrayWrapper}} { this._refObject.size = size; this._refObject.capacity = size; - {{? usePlainTypedArray}} + {{? willUseTypedArray}} this._wrappers = new {{=currentTypedArray}}(size); - {{?? true}} + {{??}} this._wrappers = new Array(); for (let i = 0; i < size; i++) { this._wrappers.push(new {{=objectWrapper}}()); @@ -783,22 +741,21 @@ 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}} + {{? willUseTypedArray}} 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 for TypedArray. */}} const arrayBuffer = refObject.data.length !== 0 ? 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]); } @@ -811,10 +768,10 @@ class {{=arrayWrapper}} { } this._resize(other.size); - {{? usePlainTypedArray}} + {{? willUseTypedArray}} this._wrappers = other._wrappers.slice(); - {{?? true}} - // Array deep copy + {{??}} + {{/* Deep copy for non-TypedArray. */}} other._wrappers.forEach((wrapper, index) => { this._wrappers[index].copy(wrapper); }); @@ -822,9 +779,8 @@ class {{=arrayWrapper}} { } static freeArray(refObject) { - {{? usePlainTypedArray}} - // For TypedArray: .data will be 'free()'-ed in parent struct - {{?? true}} + {{/* 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++) { @@ -842,7 +798,7 @@ class {{=arrayWrapper}} { } static get useTypedArray() { - return {{=usePlainTypedArray}}; + return {{=willUseTypedArray}}; } get classType() { @@ -851,14 +807,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}); -{{?? 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}}; 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';