TypeError: inspect(...).addField is not a function - node.js

var embed = new Discord.MessageEmbed()
.setColor('#f03824')
.setTitle('Evaluated')
.addField(`To Eval`, `\`\`\`${command}\`\`\``)
.addField('Evaled', `\`\`\`js\n${inspect(evaled, { depth: 0})}\`\`\``
.addField(`Type Of`, `\`\`\`${typeof(evaled)}\`\`\``))
message.channel.send(embed)
How do i fix this error?
TypeError: inspect(...).addField is not a function

You're missing a closing parentheses ) at the end of the line
.addField('Evaled', `\`\`\`js\n${inspect(evaled, { depth: 0})}\`\`\``
Add it and it should work:
.addField('Evaled', `\`\`\`js\n${inspect(evaled, { depth: 0})}\`\`\``)

Related

ExpectedConstraintError: Invalid string format discord.js

I am trying to make a slashcommandbuilder for my coinflip command but something is going on. Btw I am new to discord.js. This is the error I get.
return regex.test(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError(type, "Invalid string format", input, expected));
^
ExpectedConstraintError: Invalid string format
at Object.run (C:\Users\dhart\Desktop\Projects\ExistentialThreat\node_modules\#sapphire\shapeshift\dist\index.js:1564:64)
at C:\Users\dhart\Desktop\Projects\ExistentialThreat\node_modules\#sapphire\shapeshift\dist\index.js:142:66
at Array.reduce (<anonymous>)
at StringValidator.parse (C:\Users\dhart\Desktop\Projects\ExistentialThreat\node_modules\#sapphire\shapeshift\dist\index.js:142:29)
at validateName (C:\Users\dhart\Desktop\Projects\ExistentialThreat\node_modules\#discordjs\builders\dist\index.js:782:17)
at SlashCommandUserOption.setName (C:\Users\dhart\Desktop\Projects\ExistentialThreat\node_modules\#discordjs\builders\dist\index.js:856:5)
at C:\Users\dhart\Desktop\Projects\ExistentialThreat\commands\coinflip.js:8:37
at MixedClass._sharedAddOptionMethod (C:\Users\dhart\Desktop\Projects\ExistentialThreat\node_modules\#discordjs\builders\dist\index.js:1256:50)
at MixedClass.addUserOption (C:\Users\dhart\Desktop\Projects\ExistentialThreat\node_modules\#discordjs\builders\dist\index.js:1230:17)
at Object.<anonymous> (C:\Users\dhart\Desktop\Projects\ExistentialThreat\commands\coinflip.js:8:4) {
constraint: 's.string.regex',
given: 'my guess',
expected: 'expected /^[\\p{Ll}\\p{Lm}\\p{Lo}\\p{N}\\p{sc=Devanagari}\\p{sc=Thai}_-]+$/u.test(expected) to be true'
My code looks like this.
const { EmbedBuilder } = require("discord.js");
const { SlashCommandBuilder } = require('#discordjs/builders');
module.exports = {
data: new SlashCommandBuilder()
.setName('coinflip')
.setDescription('Returns value heads or tails.')
.addUserOption((option) => option.setName('my guess').setDescription('Enter heads or tails.').setRequired(false)),
//.addChoices({ name: 'Heads', value: 'guess heads'}, { name: 'Tails', value: 'guess tails'}, { name: 'Other', value: 'You are making a mistake. The chance of this is low.'}),
async execute(interaction) {
let coinflip = (Math.random() * 100).toFixed(0) % 2;
let embedThumbnail = `https://m.media-amazon.com/images/I/51bcZy+HZpL._AC_.jpg`;
console.log(coinflip);
let result = 'tails';
if (coinflip == 1){
result = 'heads';
embedThumbnail = `https://i.ebayimg.com/images/g/xtcAAOSwLwBaZigS/s-l400.jpg`;
}
let guess = interaction.options.getString('my guess');
let guessedmessage = 'You guessed it correct!'
if (!result == guess){
guessedmessage = 'You guessed it wrong, but good try.';
};
I would appreciate some help in fixing this issue.
The 'my guess' option is a user option, not a string option. Change it to:
.addStringOption((option) => option.setName('my guess').setDescription('Enter heads or tails.').setRequired(false)),

How to get the number of elements in protractor nodejs and how to click on particular element having the same xpath

My scenario is to add a section in a page and perform an action on it.But as there are elements with the same xpath already, webdriver is clicking on first element and the script is failing.So, I want to fetch the existing number of elements having the same xpath and then increase the count by 1 so as to click on the newly added section. Please find the below code and correct me where it is going wrong.(Or) Suggest me any other approach.
Also, please let me know will line no. 9 works if getting the number of elements issue is resolved. Thanks!
Method :
this.getElementCount=async function(locator) {
try {
console.info('Verifying count for element ' + locator);
let noOfElements = await element.all(locator).count();
await console.info('There are ' + noOfElements + 'elements in UI');
return noOfElements;
} catch(err) {
throw err;
}
}
Calling method :
var compLocator = element(by.xpath("//div[#title='Test']"));
this.clickOnComp=async function(){
var elementsCount=getElementCount(compLocator);
console.info("No. of elements : "+elementsCount);
if(elementsCount>1){
var currentEle=elementsCount+1;
var currentCompLocator=compLocator[currentEle]; // line no.9
console.info("comp locator :" +currentCompLocator);
await clickElement(currentCompLocator);
console.info("Clicked : "+currentCompLocator);
}
else{
await clickElement(compLocator);
}
}
Output :
Verifying count for element [object Object]
No. of elements : [object Promise]
(node:13915) UnhandledPromiseRejectionWarning: TypeError: Invalid locator
Start with resolving promise with await
var compLocator = element(by.xpath("//div[#title='Test']"));
this.clickOnComp=async function(){
var elementsCount=await getElementCount(compLocator); // <-----------------
console.info("No. of elements : "+elementsCount);
if(elementsCount>1){
var currentEle=elementsCount+1;
var currentCompLocator=compLocator[currentEle]; // line no.9
console.info("comp locator :" +currentCompLocator);
await clickElement(currentCompLocator);
console.info("Clicked : "+currentCompLocator);
}
else{
await clickElement(compLocator);
}
}
There are two issues in your code:
getElementCount() expects a locator argument by you give a element
(Line 9) compLocator is an element not an xpath or an element array, you can't use compLocator[currentEle]
var compXPath = "//div[#title='Test']"
var compLocator = by.xpath(compXPath);
this.clickOnComp=async function(){
var elementsCount = await getElementCount(compLocator);
console.info("No. of elements : "+elementsCount);
if(elementsCount > 1){
var currentEle = elementsCount+1;
var currentCompXPath = compXPath + "/["+ currentEle +"]" // line no.9
console.info("current Comp xpath :" +currentCompXPath);
var currentCompLocator = by.xpath(currentCompXPath)
await clickElement(currentCompLocator);
console.info("Clicked : "+currentCompLocator);
}
else{
await clickElement(compLocator);
}
}

Jimp: How to fix 'TypeError: Cannot read property of 'lineHeight' of undefined

I'm trying to use jimp to add text to an image. Where am I going wrong in the print function to receive this error.
let fileName = 'botImageTemplate.png';
let fontPerson = Jimp.loadFont(Jimp.FONT_SANS_128_BLACK).then(font => font);
Jimp.read(fileName)
.then(image => {
return image
.print(fontPerson, 50, 50, {
text: "This is my text",
alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
}, 40, 40)
.write('botTesting.png')
})
.catch(err => {
console.error(err);
});
The error message I keep getting is "TypeError: Cannot read property of 'lineHeight' of undefined"
What do I have to change to get this to work?
i dont know jimp, but can you try to add arguments: maxWidth and maxHeight.
For me it seems there are missing some properies.
https://www.npmjs.com/package/jimp

Bot framework (v4) Prompt choice in carousel using HeroCards not going to next step

I’m trying to use HeroCards along with a prompt choice in a carousel. So the options to be selected by the user are displayed as HeroCards. As soon as the user clicks in the button of a card it should goes to the next waterfall function.
Here is a working example in bot framework v3. It does work as expected.
const cards = (data || []).map(i => {
return new builder.HeroCard(session)
.title(`${i.productName} ${i.brandName}`)
.subtitle(‘product details’)
.text(‘Choose a product’)
.images([builder.CardImage.create(session, i.image)])
.buttons([builder.CardAction.postBack(session, `${i.id.toString()}`, ‘buy’)]);
});
const msg = new builder.Message(session);
msg.attachmentLayout(builder.AttachmentLayout.carousel);
msg.attachments(cards);
builder.Prompts.choice(session, msg, data.map(i => `${i.id.toString()}`), {
retryPrompt: msg,
});
Below I’m trying to do the same with bot framework v4 but it does not work. It never goes to the next function in my waterfall.
How can I do the same with v4?
…
this.addDialog(new ChoicePrompt(PRODUCTS_CAROUSEL));
…
const productOptions: Partial<Activity> = MessageFactory.carousel(
item.map((p: Product) =>
CardFactory.heroCard(
p.productName,
‘product details’,
[p.image || ''],
[
{
type: ActionTypes.PostBack,
title: ‘buy’,
value: p.id,
},
],
),
),
‘Choose a product’,
);
return await step.prompt(PRODUCTS_CAROUSEL, productOptions);
…
UPDATE:
Follow full code with the suggestion from #Drew Marsh
export class ProductSelectionDialog extends ComponentDialog {
private selectedProducts: Product[] = [];
private productResult: Product[][];
private stateAccessor: StatePropertyAccessor<State>;
static get Name() {
return PRODUCT_SELECTION_DIALOG;
}
constructor(stateAccessor: StatePropertyAccessor<State>) {
super(PRODUCT_SELECTION_DIALOG);
if (!stateAccessor) {
throw Error('Missing parameter. stateAccessor is required');
}
this.stateAccessor = stateAccessor;
const choicePrompt = new ChoicePrompt(PRODUCTS_CAROUSEL);
choicePrompt.style = ListStyle.none;
this.addDialog(
new WaterfallDialog<State>(REVIEW_PRODUCT_OPTIONS_LOOP, [
this.init.bind(this),
this.selectionStep.bind(this),
this.loopStep.bind(this),
]),
);
this.addDialog(choicePrompt);
}
private init = async (step: WaterfallStepContext<State>) => {
const state = await this.stateAccessor.get(step.context);
if (!this.productResult) this.productResult = state.search.productResult;
return await step.next();
};
private selectionStep = async (step: WaterfallStepContext<State>) => {
const item = this.productResult.shift();
const productOptions: Partial<Activity> = MessageFactory.carousel(
item.map((p: Product) =>
CardFactory.heroCard(
p.productName,
'some text',
[p.image || ''],
[
{
type: ActionTypes.ImBack,
title: 'buy',
value: p.id,
},
],
),
),
'Choose a product',
);
return await step.prompt(PRODUCTS_CAROUSEL, {
prompt: productOptions,
choices: item.map((p: Product) => p.id),
});
};
private loopStep = async (step: WaterfallStepContext<State>) => {
console.log('step.result: ', step.result);
};
}
PARENT DIALOG BELOW:
...
this.addDialog(new ProductSelectionDialog(stateAccessor));
...
if (search.hasIncompletedProducts) await step.beginDialog(ProductSelectionDialog.Name);
...
return await step.next();
...
MY BOT DIALOG STRUCTURE
onTurn()
>>> await this.dialogContext.beginDialog(MainSearchDialog.Name) (LUIS)
>>>>>> await step.beginDialog(QuoteDialog.Name)
>>>>>>>>> await step.beginDialog(ProductSelectionDialog.Name)
UPDATE
Replacing the ChoicePrompt with TextPromt (as suggested by Kyle Delaney) seems to have the same result (do not go to the next step) but I realised that if remove return from the prompt like this:
return await step.prompt(PRODUCTS_CAROUSEL, `What is your name, human?`); TO await step.prompt(PRODUCTS_CAROUSEL, `What is your name, human?`);
it does work but when I'm returning the original code with ChoicePrompt without return like this:
await step.prompt(PRODUCTS_CAROUSEL, {
prompt: productOptions,
choices: item.map((p: Product) => p.id),
});
I'm getting another error in the framework:
error: TypeError: Cannot read property 'length' of undefined
at values.sort (/xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/choices/findValues.js:84:48)
at Array.sort (native)
at Object.findValues (/xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/choices/findValues.js:84:25)
at Object.findChoices (/xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/choices/findChoices.js:58:25)
at Object.recognizeChoices (/xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/choices/recognizeChoices.js:75:33)
at ChoicePrompt.<anonymous> (/xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/prompts/choicePrompt.js:62:39)
at Generator.next (<anonymous>)
at /xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/prompts/choicePrompt.js:7:71
at new Promise (<anonymous>)
at __awaiter (/xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/prompts/choicePrompt.js:3:12)
this is the line:
// Sort values in descending order by length so that the longest value is searched over first.
const list = values.sort((a, b) => b.value.length - a.value.length);
I can see the data from my state is coming properly
prompt: <-- the data is ok
choices: <-- the data is ok too
Sometimes I'm getting this error too:
error: TypeError: Cannot read property 'status' of undefined
at ProductSelectionDialog.<anonymous> (/xxxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/componentDialog.js:92:28)
at Generator.next (<anonymous>)
at fulfilled (/xxxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/componentDialog.js:4:58)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
this line
// Check for end of inner dialog
if (turnResult.status !== dialog_1.DialogTurnStatus.waiting) {
You're using a ChoicePrompt, but when you call prompt you're only passing through an activity (the carousel). ChoicePrompt is going to try to validate the input against a set of choices that you should be passing in when you call prompt. Because you're not doing this, the prompt is not recognizing the post back value as valid and technically should be reprompting you with the carousel again to make a valid choice.
The fix here should be to call prompt with PromptOptions instead of just a raw Activity and set the choices of the PromptOptions to an array that contains all the values you expect back (e.g. the same value you set for the value of the post back button).
This should end up looking a little something like this:
Since you're providing the choices UX with your cards, you want to set the ListStyle on the ChoicePrompt to none
const productsPrompt = new ChoicePrompt(PRODUCTS_CAROUSEL);
productsPrompt.style = ListStyle.none;
this.addDialog(productsPrompt);
Then, set the available choices for the specific prompt:
return await step.prompt(PRODUCTS_CAROUSEL, {
prompt: productOptions,
choices: items.map((p: Product) => p.id),
});
Basically Drew Marsh was right.
I just would like to add some other details that I had to tweak to make it work. In case someone else is going crazy like I was. It could give some insights. It's all about how you handle the returns of nested dialogs.
First change. I had to transform the identifier of the Choice prompt into string:
{
type: ActionTypes.PostBack,
title: 'buy',
value: p.id.toString(),
},
and
return await step.prompt(PRODUCTS_CAROUSEL, {
prompt: productOptions,
choices: item.map((p: Product) => p.id.toString()),
});
Another problem that I found was in the parent dialog:
I was basically trying to do this:
if (search.hasIncompletedProducts) await step.beginDialog(ProductSelectionDialog.Name);
return await step.next();
Which makes no sense, then I changed it to:
if (search.hasIncompletedProducts) {
return await step.beginDialog(ProductSelectionDialog.Name);
} else {
return await step.next();
}
And then the final change in the parent of the parent dialog:
Before was like this:
switch (step.result) {
case ESearchOptions.OPT1:
await step.beginDialog(OPT1Dialog.Name);
break;
default:
break;
}
await step.endDialog();
Which again does not make sense since I should return the beginDialog or endDialog. It was changed to:
switch (step.result) {
case ESearchOptions.OPT1:
return await step.beginDialog(OPT1Dialog.Name);
default:
break;
}

forEach using generators in Node.js

I'm using Koa.js framework and Mongoose.js module.
Normally to get a result from MongoDB I code like this:
var res = yield db.collection.findOne({id: 'my-id-here'}).exec();
But I need to execute this line for every element of an array named 'items'.
items.forEach(function(item) {
var res = yield db.collection.findOne({id: item.id}).exec();
console.log(res) // undefined
});
But this code doesn't run as yield is in the function. If I write this:
items.forEach(function *(item) {
var res = yield db.collection.findOne({id: item.id}).exec();
console.log(res) // undefined
});
I'm not getting the result in res variable either. I tried to use 'generator-foreach' module but that didn't worked like this.
I know that this is my lack of knowledge about the language literacy of Node.js. But can you guys help me finding a way how to do this?
You can yield arrays, so just map your async promises in another map
var fetchedItems = yield items.map((item) => {
return db.collection.findOne({id: item.id});
});
The accepted answer is wrong, there is no need to use a library, an array is already an iterable.
This is an old question, but since it has no correct answer yet and it appears on the first page on google search for the key terms "iterators and forEach" I will respond the question:
There is no need to iterate over an array, since an array already conforms to the iterable API.
inside your generator just use "yield* array" (note the * )
yield* expression is used to delegate to another generator or iterable object
Example:
let arr = [2, 3, 4];
function* g2() {
yield 1;
yield* arr;
yield 5;
}
var iterator = g2();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: 4, done: false }
console.log(iterator.next()); // { value: 5, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
For examples and in depth information visit:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield*
Thanks guys, I've done this using the 'CO' module. Thanks.
var co = require('co');
items.forEach(co(function* (item) {
var img = yield db.collection.findOne({id: item.id}).exec();
}));
EDIT: With the latest version of CO, you need co.wrap() for this to work.

Resources