Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions lib/Deprecated.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,46 @@ class iPgm {
* @param {string | array} data
* @param {string} [type]
* @param {object} options
* @param {*} inDs
*/
addParam(data, type, options, inDs) {
if (!Array.isArray(data) && !type) {
iPgmDeprecate('defaulting parameter type to 1024a has been deprecated. You should specify a type instead.');
// eslint-disable-next-line no-param-reassign
type = '1024a';
addParam(data, type, options) {
const parameter = {};

if (Array.isArray(data)) { // DS parameter
parameter.type = 'ds';
parameter.fields = [];

if (typeof type === 'object') { // <ds> options
Object.keys(type).forEach((key) => {
parameter[key] = type[key];
});
}
// convert 2D Array into fields [] of data objects
for (let i = 0; i < data.length; i += 1) {
const field = { type: data[i][1], value: data[i][0] };
if (typeof data[i][2] === 'object') {
Object.keys(data[i][2]).forEach((key) => { // <data> options
field[key] = data[i][2][key];
});
}
parameter.fields.push(field);
}
} else {
parameter.type = type;
parameter.value = data;
if (!type) {
iPgmDeprecate('defaulting parameter type to 1024a has been deprecated. You should specify a type instead.');
parameter.type = '1024a';
}

if (typeof options === 'object') { // <data> options
Object.keys(options).forEach((key) => {
parameter[key] = options[key];
});
}
}

iPgmDeprecate('As of v1.0, \'iPgm.addParam()\' is deprecated. Please use \'ProgramCall.addParam()\' instead.');
return this.ProgramCall.addParam(data, type, options, inDs);
return this.ProgramCall.addParam(parameter);
}

/**
Expand Down
95 changes: 50 additions & 45 deletions lib/ProgramCall.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/* eslint-disable no-underscore-dangle */

class ProgramCall {
/**
* @description creates a new ProgramCall object
Expand All @@ -31,59 +33,62 @@ class ProgramCall {
}

/**
* @description adds a parameter to the program XML
* @param {string | array} data
* @param {string} [type]
* @param {object} options
* @param {*} inDs
*/
addParam(data, type, options, inDs = null) {
let opt;
// DS element has no 'type', so if the second param 'type' is an Object, then it is the options.
if (Array.isArray(data)) {
opt = type;
} else {
opt = options;
if (type === undefined) {
throw new Error('Specifying the parameter type is required.');
}
}
if (!inDs) { // In recursive mode, if it is an element in DS, then no <parm> or </parm> needed.
this.xml += '<parm';
if (opt && typeof opt === 'object') { // append <param> options
if (opt.io) { this.xml += ` io='${opt.io}'`; }
if (opt.by) { this.xml += ` by='${opt.by}'`; }
}
this.xml += '>';
}

if (Array.isArray(data)) { // If it is a struct parameter, recursively parse its children.
* Internal function to handle ds and data within <parm> node
* There is an open propsal to add private methods to JS.
* https://github.com/tc39/proposal-private-methods
* We should update to use private methods in the future.
* @param {object} data
*/
__addData__(data = {}) {
if (data.type === 'ds') {
this.xml += '<ds';
if (opt && typeof opt === 'object') { // append <ds> options
if (opt.dim) { this.xml += ` dim='${opt.dim}'`; }
if (opt.dou) { this.xml += ` dou='${opt.dou}'`; }
if (opt.len) { this.xml += ` len='${opt.len}'`; }
if (opt.data) { this.xml += ` data='${opt.data}'`; }
}
// append <ds> options
if (data.name) { this.xml += ` name='${data.name}'`; }
if (data.dim) { this.xml += ` dim='${data.dim}'`; }
if (data.dou) { this.xml += ` dou='${data.dou}'`; }
if (data.len) { this.xml += ` len='${data.len}'`; }
if (data.data) { this.xml += ` data='${data.data}'`; }
this.xml += '>';

for (let i = 0; i < data.length; i += 1) {
this.addParam(data[i][0], data[i][1], data[i][2], true);
for (let i = 0; i < data.fields.length; i += 1) {
this.__addData__(data.fields[i]);
}
this.xml += '</ds>';
} else { // A simple parameter
this.xml += `<data type='${type}'`;
if (opt && typeof opt === 'object') { // append <data> options
Object.keys(opt).forEach((key) => {
this.xml += ` ${key}='${opt[key]}'`;
});
}
this.xml += `>${data}</data>`;
} else {
this.xml += `<data type='${data.type}'`;
// append <data> options
if (data.name) { this.xml += ` name='${data.name}'`; }
if (data.varying) { this.xml += ` varying='${data.varying}'`; }
if (data.enddo) { this.xml += ` enddo='${data.enddo}'`; }
if (data.setlen) { this.xml += ` setlen='${data.setlen}'`; }
if (data.offset) { this.xml += ` offset='${data.offset}'`; }
if (data.hex) { this.xml += ` hex='${data.hex}'`; }
if (data.trim) { this.xml += ` trim='${data.trim}'`; }
if (data.next) { this.xml += ` next='${data.next}'`; }
this.xml += `>${data.value}</data>`;
}
}

if (!inDs) { // In recursive mode, if it is an element in DS, then no <parm> or </parm> needed.
this.xml += '</parm>';
/**
* @description adds a parameter to the program XML
* @param {object} parmeter
*/
addParam(parameter = {}) {
if (typeof parameter !== 'object') {
throw new Error('Expected the first parameter to be an object');
}
if (parameter.type === undefined) {
throw new Error('Expected \'type\' key on the parameter object');
}
this.xml += '<parm';

if (parameter.name) { this.xml += ` name='${parameter.name}'`; }
if (parameter.io) { this.xml += ` io='${parameter.io}'`; }
if (parameter.by) { this.xml += ` by='${parameter.by}'`; }

this.xml += '>';
this.__addData__(parameter);
this.xml += '</parm>';
}

/**
Expand Down
60 changes: 34 additions & 26 deletions test/unit/ProgamCallUnit.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,20 @@ const { expect } = require('chai');
const { ProgramCall } = require('../../lib/itoolkit');

const outBuf = [
[0, '10i0'],
[0, '10i0'],
['', '36h'],
['', '10A'],
['', '1A'],
['', '1A'],
[0, '10i0'],
[0, '10i0'],
{ type: '10i0', value: 0 },
{ type: '10i0', value: 0 },
{ type: '36h', value: '' },
{ type: '10A', value: '' },
{ type: '1A', value: '' },
{ type: '1A', value: '' },
{ type: '10i0', value: 0 },
{ type: '10i0', value: 0 },
];
const errno = [
[0, '10i0'],
[0, '10i0', { setlen: 'rec2' }],
['', '7A'],
['', '1A'],
{ type: '10i0', value: 0 },
{ type: '10i0', value: 0, setlen: 'rec2' },
{ type: '7A', value: '' },
{ type: '1A', value: '' },
];

describe('ProgramCall Class Unit Tests', () => {
Expand Down Expand Up @@ -71,7 +71,7 @@ describe('ProgramCall Class Unit Tests', () => {
error: 'fast',
});

pgm.addParam(outBuf, { io: 'out' });
pgm.addParam({ type: 'ds', io: 'out', fields: outBuf });

let expectedXML = '<pgm name=\'QTOCNETSTS\' lib=\'QSYS\' func=\'QtoRtvTCPA\' error=\'fast\'>'
+ '<parm io=\'out\'><ds><data type=\'10i0\'>0</data><data type=\'10i0\'>'
Expand All @@ -81,7 +81,7 @@ describe('ProgramCall Class Unit Tests', () => {

expect(pgm.toXML()).to.equal(expectedXML);

pgm.addParam(66, '10i0');
pgm.addParam({ value: 66, type: '10i0' });

expectedXML = '<pgm name=\'QTOCNETSTS\' lib=\'QSYS\' func=\'QtoRtvTCPA\' error=\'fast\'>'
+ '<parm io=\'out\'><ds><data type=\'10i0\'>0</data><data type=\'10i0\'>'
Expand All @@ -92,7 +92,7 @@ describe('ProgramCall Class Unit Tests', () => {

expect(pgm.toXML()).to.equal(expectedXML);

pgm.addParam(1, '10i0');
pgm.addParam({ value: 1, type: '10i0' });

expectedXML = '<pgm name=\'QTOCNETSTS\' lib=\'QSYS\' func=\'QtoRtvTCPA\' error=\'fast\'>'
+ '<parm io=\'out\'><ds><data type=\'10i0\'>0</data><data type=\'10i0\'>'
Expand All @@ -104,7 +104,7 @@ describe('ProgramCall Class Unit Tests', () => {

expect(pgm.toXML()).to.equal(expectedXML);

pgm.addParam('QCCSID', '10A');
pgm.addParam({ value: 'QCCSID', type: '10A' });

expectedXML = '<pgm name=\'QTOCNETSTS\' lib=\'QSYS\' func=\'QtoRtvTCPA\' error=\'fast\'>'
+ '<parm io=\'out\'><ds><data type=\'10i0\'>0</data><data type=\'10i0\'>'
Expand All @@ -117,7 +117,9 @@ describe('ProgramCall Class Unit Tests', () => {

expect(pgm.toXML()).to.equal(expectedXML);

pgm.addParam(errno, { io: 'both', len: 'rec2' });
pgm.addParam({
type: 'ds', io: 'both', len: 'rec2', fields: errno,
});

expectedXML = '<pgm name=\'QTOCNETSTS\' lib=\'QSYS\' func=\'QtoRtvTCPA\' error=\'fast\'>'
+ '<parm io=\'out\'><ds><data type=\'10i0\'>0</data><data type=\'10i0\'>'
Expand All @@ -137,8 +139,8 @@ describe('ProgramCall Class Unit Tests', () => {
it('regular <parm> contains by=\'val\'', () => {
const pgm = new ProgramCall('MYPGM', { lib: 'MYLIB', func: 'MY_PROCEDURE' });

pgm.addParam('', '1A', { by: 'val' });
pgm.addReturn('', '2A', { name: 'output' });
pgm.addParam({ value: '', type: '1A', by: 'val' });
pgm.addReturn('', '2A', 'output');

const lookAtXML = pgm.toXML();
expect(lookAtXML).to.match(/<parm .*by='val'.*>/);
Expand All @@ -148,11 +150,13 @@ describe('ProgramCall Class Unit Tests', () => {
const pgm = new ProgramCall('MYPGM', { lib: 'MYLIB', func: 'MY_PROCEDURE' });

const params = [
[0, '3s0'],
[0, '7s0', { name: 'ds_fld2' }],
{ type: '3s0', value: 0 },
{ type: '7s0', value: 0, name: 'ds_fld2' },
];

pgm.addParam(params, { name: 'inds', by: 'val' });
pgm.addParam({
name: 'inds', type: 'ds', by: 'val', fields: params,
});
pgm.addReturn('', '2A', { name: 'output' });

const lookAtXML = pgm.toXML();
Expand All @@ -162,7 +166,9 @@ describe('ProgramCall Class Unit Tests', () => {
it('regular <parm> contains by=\'val\', with io=\'both\'', () => {
const pgm = new ProgramCall('MYPGM', { lib: 'MYLIB', func: 'MY_PROCEDURE' });

pgm.addParam('', '1A', { by: 'val', io: 'both' });
pgm.addParam({
value: '', type: '1A', by: 'val', io: 'both',
});
pgm.addReturn('', '2A', { name: 'output' });

const lookAtXML = pgm.toXML();
Expand All @@ -174,11 +180,13 @@ describe('ProgramCall Class Unit Tests', () => {
const pgm = new ProgramCall('MYPGM', { lib: 'MYLIB', func: 'MY_PROCEDURE' });

const params = [
[0, '3s0'],
[0, '7s0', { name: 'ds_fld2' }],
{ type: '3s0', value: 0 },
{ type: '7s0', value: 0, name: 'ds_fld2' },
];

pgm.addParam(params, { name: 'inds', by: 'val', io: 'both' });
pgm.addParam({
name: 'inds', type: 'ds', by: 'val', io: 'both', fields: params,
});
pgm.addReturn('', '2A', { name: 'output' });

const lookAtXML = pgm.toXML();
Expand Down