Skip to content

Commit

Permalink
fix: parse order of parameters from function source code (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
kakhaUrigashvili authored Apr 10, 2020
1 parent d584040 commit 7859681
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 30 deletions.
8 changes: 6 additions & 2 deletions lib/commands/smapi/cli-customization-processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ class CliCustomizationProcessor {
return definitions.get(schema);
}

_shouldParseAsJson(property) {
return property.type === 'object' || (property.type === 'array' && '$ref' in property.items);
}

_appendSecondLevelProperty(customizationMetadata, parentName, rootName, secondLevelDefinition, required, definitions) {
let customizedParameter;
const parentDescription = secondLevelDefinition.description;
Expand All @@ -106,7 +110,7 @@ class CliCustomizationProcessor {
enumOptions = schema.enum;
description = schema.description || description;
}
const json = property.type === 'object';
const json = this._shouldParseAsJson(property);
const bodyPath = `${parentName}${BODY_PATH_DELIMITER}${key}`;
customizedParameter = { name: `${parentName} ${key}`, description, rootName, required, bodyPath, enum: enumOptions, json };
this._addCustomizedParameter(customizationMetadata, customizedParameter);
Expand All @@ -130,7 +134,7 @@ class CliCustomizationProcessor {
this._appendSecondLevelProperty(customizationMetadata, key, rootName, secondLevelDefinition, isRequired, definitions);
} else {
const { description } = property;
const json = property.type === 'object';
const json = this._shouldParseAsJson(property);
// required inherited from parent param
const customizedParameter = { name: key, description, rootName, required: param.required, bodyPath: key, json };
this._addCustomizedParameter(customizationMetadata, customizedParameter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/
const mapTestersEmails = (requestParameters) => {
const { testersEmails } = requestParameters;
requestParameters.TestersRequest = {
requestParameters.testersRequest = {
testers: testersEmails.map(email => ({ emailId: email }))
};

Expand Down
35 changes: 24 additions & 11 deletions lib/commands/smapi/customizations/smapi-hooks.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const { ModelIntrospector } = require('ask-smapi-sdk');
const appendVendorId = require('@src/commands/smapi/customizations/hook-functions/append-vendor-id');
const mapTestersEmails = require('@src/commands/smapi/customizations/hook-functions/map-testers-emails');

Expand All @@ -7,19 +8,31 @@ const events = {

const operationHooks = new Map();

operationHooks.set('createSkillForVendorV1', new Map([[events.BEFORE_SEND, appendVendorId]]));
operationHooks.set('createIspForVendorV1', new Map([[events.BEFORE_SEND, appendVendorId]]));
operationHooks.set('getIspListForVendorV1', new Map([[events.BEFORE_SEND, appendVendorId]]));
operationHooks.set('getAlexaHostedSkillUserPermissionsV1', new Map([[events.BEFORE_SEND, appendVendorId]]));
operationHooks.set('listInteractionModelCatalogsV1', new Map([[events.BEFORE_SEND, appendVendorId]]));
operationHooks.set('listInteractionModelSlotTypesV1', new Map([[events.BEFORE_SEND, appendVendorId]]));
operationHooks.set('listSkillsForVendorV1', new Map([[events.BEFORE_SEND, appendVendorId]]));
operationHooks.set('addTestersToBetaTestV1', new Map([[events.BEFORE_SEND, mapTestersEmails]]));
operationHooks.set('removeTestersFromBetaTestV1', new Map([[events.BEFORE_SEND, mapTestersEmails]]));
operationHooks.set('sendReminderToTestersV1', new Map([[events.BEFORE_SEND, mapTestersEmails]]));
operationHooks.set('requestFeedbackFromTestersV1', new Map([[events.BEFORE_SEND, mapTestersEmails]]));
const _autoRegisterHooks = () => {
const modelIntrospector = new ModelIntrospector();
const operations = modelIntrospector.getOperations();
operations.forEach(operation => {
operation.params.forEach(param => {
switch (param.name) {
case 'vendorId':
operationHooks.set(operation.apiOperationName, new Map([[events.BEFORE_SEND, appendVendorId]]));
break;
case 'TestersRequest':
operationHooks.set(operation.apiOperationName, new Map([[events.BEFORE_SEND, mapTestersEmails]]));
break;
default:
}
});
});
};

const _manualRegisterHooks = () => {
operationHooks.set('createIspForVendorV1', new Map([[events.BEFORE_SEND, appendVendorId]]));
operationHooks.set('createSkillForVendorV1', new Map([[events.BEFORE_SEND, appendVendorId]]));
};

_autoRegisterHooks();
_manualRegisterHooks();
class SmapiHooks {
/**
* Returns object with available hook events.
Expand Down
19 changes: 11 additions & 8 deletions lib/commands/smapi/smapi-command-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const jsonView = require('@src/view/json-view');
const Messenger = require('@src/view/messenger');
const profileHelper = require('@src/utils/profile-helper');
const unflatten = require('@src/utils/unflatten');
const { getParamNames } = require('@src/utils/string-utils');

const { BODY_PATH_DELIMITER, ARRAY_SPLIT_DELIMITER } = require('./cli-customization-processor');
const SmapiHooks = require('./customizations/smapi-hooks');
Expand All @@ -18,12 +19,13 @@ const configFilePath = path.join(os.homedir(), CONSTANTS.FILE_PATH.ASK.HIDDEN_FO
const _mapToArgs = (params, paramsObject) => {
const res = [];
params.forEach(param => {
const { name } = param;
if (paramsObject[name]) {
res.push(paramsObject[name]);
} else {
res.push(null);
}
let value = null;
Object.keys(paramsObject).forEach(k => {
if (k.toLowerCase() === param.toLowerCase()) {
value = paramsObject[k];
}
});
res.push(value);
});
return res;
};
Expand Down Expand Up @@ -62,7 +64,7 @@ const _mapToParams = (optionsValues, flatParamsMap, commanderToApiCustomizationM
* for api properties.
* @param {Object} cmdObj Commander object with passed values.
*/
const smapiCommandHandler = (swaggerApiOperationName, swaggerParams, flatParamsMap, commanderToApiCustomizationMap, inputCmdObj) => {
const smapiCommandHandler = (swaggerApiOperationName, flatParamsMap, commanderToApiCustomizationMap, inputCmdObj) => {
new AppConfig(configFilePath);
const authorizationController = new AuthorizationController({
auth_client_type: 'LWA'
Expand Down Expand Up @@ -90,7 +92,8 @@ const smapiCommandHandler = (swaggerApiOperationName, swaggerParams, flatParamsM
Messenger.getInstance().info('Payload:');
Messenger.getInstance().info(jsonView.toString(paramsObject));
}
const args = _mapToArgs(swaggerParams, paramsObject);
const params = getParamNames(client[swaggerApiOperationName]);
const args = _mapToArgs(params, paramsObject);
return client[swaggerApiOperationName](...args);
};

Expand Down
1 change: 0 additions & 1 deletion lib/commands/smapi/smapi-commander.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ const makeSmapiCommander = () => {
});
commanderInstance.action((inputCmdObj) => smapiCommandHandler(
apiOperationName,
operation.params,
flatParamsMap,
commanderToApiCustomizationMap,
inputCmdObj
Expand Down
10 changes: 10 additions & 0 deletions lib/utils/string-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const R = require('ramda');
const CONSTANTS = require('@src/utils/constants');

module.exports = {
getParamNames,
camelCase,
kebabCase,
isNonEmptyString,
Expand All @@ -12,6 +13,15 @@ module.exports = {
validateSyntax
};

function getParamNames(func) {
const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
const ARGUMENT_NAMES = /([^\s,]+)/g;
const fnStr = func.toString().replace(STRIP_COMMENTS, '');
let result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
if (result === null) result = [];
return result;
}

function camelCase(str) {
return str
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => (index === 0 ? word.toLowerCase() : word.toUpperCase()))
Expand Down
7 changes: 6 additions & 1 deletion test/unit/commands/smapi/cli-customization-processor-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe('Smapi test - CliCustomizationProcessor class', () => {
const nestedPropertyName = 'nestedProperty';
const nestedEnumPropertyName = 'nestedEnumProperty';
const bodyProperty = {};
const bodyPropertyWithArray = { type: 'array', items: { $ref: 'test' } };
const bodyPropertyWithDescription = { description: 'property description' };
const nestedProperty = { $ref: 'SomeObjectType' };
const nestedEnumProperty = { $ref: 'SomeEnumTypeWithDescription' };
Expand All @@ -57,7 +58,11 @@ describe('Smapi test - CliCustomizationProcessor class', () => {
['SomeEnumTypeWithDescription', { enum: enumValues, description: enumDescription }],
['SomeTypeWithDescription', { enum: enumValues, description: refObjectDescription }],
['SomeObjectType', { description: parentDescription,
properties: { propertyOne: bodyProperty, propertyTwo: bodyPropertyWithDescription } }],
properties: { propertyOne: bodyProperty,
propertyTwo: bodyPropertyWithDescription,
propertyThree: { $ref: 'SomeEnumType' },
propertyFour: { $ref: 'SomeEnumTypeWithDescription' },
propertyFive: bodyPropertyWithArray } }],
['SomeNestedType', { required: [nestedPropertyName],
properties: { nestedProperty } }],
['SomeTooManyPropertiesType', { properties: { ...objectWithTooManyProperties } }],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ const mapTestersEmails = require('@src/commands/smapi/customizations/hook-functi


describe('Smapi hook functions test - mapTestersEmails tests', () => {
it('| should map testers emails to TestersRequest parameter', () => {
it('| should map testers emails to testersRequest parameter', () => {
const requestParameters = { testersEmails: ['tester1', 'tester2'] };

mapTestersEmails(requestParameters);

const expected = { testers: [{ emailId: 'tester1' }, { emailId: 'tester2' }] };

expect(requestParameters.TestersRequest).eql(expected);
expect(requestParameters.testersRequest).eql(expected);
});
});
10 changes: 6 additions & 4 deletions test/unit/commands/smapi/smapi-command-handler-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,16 @@ describe('Smapi test - smapiCommandHandler function', () => {
}
});
clientStub[apiOperationName] = sinon.stub().resolves();
clientStub[apiOperationName].toString = () => 'function (someJson, skillId, '
+ 'someNonPopulatedProperty, someArray, simulationsApiRequest) { return 0};';
sinon.stub(StandardSmapiClientBuilder.prototype, 'client').returns(clientStub);
});


it('| should send smapi command with correct parameter mapping', async () => {
await smapiCommandHandler(apiOperationName, params, flatParamsMap, commanderToApiCustomizationMap, cmdObj);
await smapiCommandHandler(apiOperationName, flatParamsMap, commanderToApiCustomizationMap, cmdObj);

const expectedParams = [skillId, null, { input: { content: inputContent }, device: { locale: deviceLocale } }, jsonValue, arrayValue];
const expectedParams = [jsonValue, skillId, null, arrayValue, { input: { content: inputContent }, device: { locale: deviceLocale } }];
const calledParams = clientStub[apiOperationName].args[0];

expect(calledParams).eql(expectedParams);
Expand All @@ -73,7 +75,7 @@ describe('Smapi test - smapiCommandHandler function', () => {
const stubHook = sinon.stub();
sinon.stub(SmapiHooks, 'getFunction').returns(stubHook);

await smapiCommandHandler(apiOperationName, params, flatParamsMap, commanderToApiCustomizationMap, cmdObj);
await smapiCommandHandler(apiOperationName, flatParamsMap, commanderToApiCustomizationMap, cmdObj);

expect(stubHook.calledOnce).eql(true);
});
Expand All @@ -87,7 +89,7 @@ describe('Smapi test - smapiCommandHandler function', () => {

const messengerStub = sinon.stub(Messenger, 'displayMessage');

await smapiCommandHandler(apiOperationName, params, flatParamsMap, commanderToApiCustomizationMap, cmdObjDebug);
await smapiCommandHandler(apiOperationName, flatParamsMap, commanderToApiCustomizationMap, cmdObjDebug);

expect(messengerStub.args[0]).eql(['INFO', 'Operation: someApiOperation']);
expect(messengerStub.args[1]).eql(['INFO', 'Payload:']);
Expand Down

0 comments on commit 7859681

Please sign in to comment.