The Problem:
I'm currently improving the valid-expect rule for the eslint-plugin-jasmine package trying to handle one more invalid Jasmine expect() usage when a matcher is not called:
expect(true).toBeDefined;
Valid usage:
expect(true).toBeDefined();
I'm getting pretty close - I can determine that there is a member expression on the expect():
// matcher was not called
MemberExpression: function (node) {
if (node.object && node.object.callee.name === 'expect') {
console.log(node.property)
}
}
But the node.property in both valid and invalid cases is of an Identifier type:
Node {
type: 'Identifier',
start: 13,
end: 24,
loc:
SourceLocation {
start: Position { line: 1, column: 13 },
end: Position { line: 1, column: 24 } },
range: [ 13, 24 ],
name: 'toBeDefined' }
And there is nothing obvious indicating that this is a property or a method.
The Question:
How can I determine if a property is callable or not in ESLint?
expect(true).toBeDefined is parsed into a MemberExpression node, but expect(true).toBeDefined() is parser into a CallExpression. I'm not really 100% sure why this is happening, but in the second case, it seems to think that the whole statement up until opening brackets is one single CallExpression, I would expect there to be two separate CallExpression, but that doesn't seems to be the case.
So what you can do is listen to CallExpression and check that callee is Identifier with name expect. And then check if it's grandparent is a MemberExpression or another CallExpression.
Related
Working with nodejs and neo4j. I have the node-label: Product. one of it's properties is entries: which is a stringfied json, that contain nested objects of type - entry.
when ever a user enter a product link, the amount of it's entry is incremented.
e.g: Entering the product link from Facebook page, amount of facebookPage entry should be incremented.
(productId and entry are arguments of the server-endpoint that route to that query. )
the current query:
MATCH (p:Product {id: $prodcutId})
WITH apoc.convert.fromJsonMap(p.entries).facebookPage AS jsonEntries, p
SET p.entries = apoc.convert.toJson({facebookPage: { link: jsonEntries.link, amount: jsonEntries.amount + 1}})
RETURN p as product
with one entry (facebookPage), the query is working fine.
but with more than one(e.g: instagramPage), i need a way to save the former entries data.
with javascript i would have done something like this:
SET p.entries = apoc.convert.toJson({...jsonEntries, $entry: { link: jsonEntries.link, amount: jsonEntries.amount + 1, min: 1 }}})
Is there a way to achieve this behavior ?
i saw the APOC dot notation for destructing json object.
link to the docs
using it with my case, it would look something like this
MATCH (p:Product {id: 'b80a61ea4a40408f847214fa3ccf9067'})
WITH apoc.convert.fromJsonMap(l.entries) AS jsonEntries, l
SET l.entries = apoc.convert.toJson(jsonEntries{.instagramPage, facebookPage: { link: jsonEntries.facebookPage.link, amount: jsonEntries.amount + 1 }})
RETURN l as p
but this requires specifying any of the entries, which isn't desired. There will be a lot of entries, and it will make the query hard to maintain. also, the query will need to be updated any time there is a new entry.
product structure:
{
"entries": "{"facebookPage":{"amount":1,"link":"www.facebook.com"},"instagram":{"amount":1,"link":"www.IG.com"}}",
"id": "b80a61ea4a40408f847214fa3ccf9067",
"title": "Guitar"
}
}
entry structure:
{
amount: 0,
link: 'some-link.com',
}
The destructuring you're using there isn't an APOC feature but just vanilla Neo4j. You can destructure all properties using the .* selector - see the last example on the map projection documentation page.
For you then, we'd replace .instagramPage with .*:
MATCH (p:Product {id: 'b80a61ea4a40408f847214fa3ccf9067'})
WITH apoc.convert.fromJsonMap(l.entries) AS jsonEntries, l
SET l.entries = apoc.convert.toJson(jsonEntries{.*, facebookPage: { link: jsonEntries.facebookPage.link, amount: jsonEntries.amount + 1 }})
RETURN l as p
Here's a minimal example showing .* working just to play around with:
WITH {instagramPage: {link: "instagram.com"}} AS entry
RETURN entry {.*, facebookPage: {link: "facebook.com"}}
Output:
{
"facebookPage": {
"link": "facebook.com"
},
"instagramPage": {
"link": "instagram.com"
}
}
Happily, destructuring this way also replaces existing fields in the map with updated values when there's a collision:
WITH {instagramPage: {link: "instagram.com"}} AS entry
RETURN entry {.*, instagramPage: {link: "newinstagram.com"}}
Output:
{
"instagramPage": {
"link": "newinstagram.com"
}
}
I am new to the rules engine and I am trying to create a rules engine in javascript.
I have the following rule and Passing one parameter as the wrong input, how to find which argument (fact) is mismatched (not the rule).
engine.addRule({
conditions: {
all: [{
fact: 'score',
operator: 'greaterThanInclusive',
value: 200
}, {
fact: 'players',
operator: 'equal',
value: 10
}]
},
event: {
type: 'success',
}
})
let fact = {
score: 150,
players: 10
}
It will fail the rule. How do I know which fact cause the failure of rule?
We gives a property event which will fired when rules match . If rules match the length of events going to be greater than 0.
Example:
const { events } = await engine.run(facts);
if (events.length > 0) {
return true
}
In the case of failure of rule events length going to be zero.
I would query only a part of my document but without precising any value to retrieve, just to avoid to query the whole document. I have seen the different queries, even the where query, but seems all require a value to match with the document's properties,
for example:
here my Model.Schema:
const ScheduleSchema=new Schema({
month:{type: Number, required:true},
day:{type: Number, required:true},
hour:{
morning: {
time: [{
timePlot:String,
prospect:[{
type: documentType,
ref:"Prospect"
}]
}]
},
afternoon:{
time: [{
timePlot:String,
prospect:[{
type: documentType,
ref:"Prospect"
}]
}]
}
}
})
How would only fetch the afternoon section for example, however, the queries I have seen so far ask to me to provide some value to match with my path, so my question is how query for a subpath providing only the path instead of path:value. For example as following
Model.find({path: afternoon}, () => {...}
any hint would be great,
thanks
Specifying which parts of the document to return is done by providing a projection argument to find as the second parameter:
Model.find({path: afternoon}, 'path', () => {...}
I have this function on an object that I need to trace REALLY BADLY, along with the parent caller of the invocation and arguments passed to the caller.
This well works until minified:
var foo = {
FunctionToBeLogged: function GiveMeAName() {
console.log('> %s called from %s - args: %o',
arguments.callee.name,
arguments.callee.caller.name,
arguments.callee.caller.arguments);
}
}
var bar = {
A: function A(something) {
foo.FunctionToBeLogged('nothing', 12, true);
},
B: function B(whatever, doesntMatter) {
foo.FunctionToBeLogged('nothing', 12, true);
}
}
bar.A(1.2, 'Fred', { }); // > GiveMeAName called from A - args: [1.2, "Fred", Object]
bar.B('Barney', 42, false); // > GiveMeAName called from B - args: ["Barney", 42, false]
Minification gets rid of the these names and my output becomes:
bar.A(1.2, 'Fred', { }); // > called from - args: [1.2, "Fred", Object]
bar.B('Barney', 42, false); // > called from - args: ["Barney", 42, false]
I really don't want to go and create function declarations and assignments because I have TONS of them (I inherited this code with 7,564... and I can easily run some regex sub to name the function expressions.)
What can I do to prevent the minifier to get rid of my these function names?
To achieve this you can pass specific names to not be mangled, for example in UglifyJS:
To avoid that, you can use --reserved-file to pass a filename that should contain the names to be excluded from mangling
In that file you would have a list of names you do not want to be changed like so:
{
"vars": [ "define", "require", ... ],
"props": [ "length", "prototype", ... ]
}
Uglify Mangle options docs...
I'm studying through the tutorial at http://reactivex.io/learnrx/. I'm on Exercise 19 - Reducing with an Initial Value: Sometimes when we reduce an array, we want the reduced value to be a different type than the items stored in the array. Let's say we have an array of videos and we want to reduce them to a single map where the key is the video id and the value is the video's title.
As far as the tutorial is concerned, I've solved it:
function exercise19() {
var videos = [
{
"id": 65432445,
"title": "The Chamber"
},
{
"id": 675465,
"title": "Fracture"
},
{
"id": 70111470,
"title": "Die Hard"
},
{
"id": 654356453,
"title": "Bad Boys"
}
];
return videos.reduce(function(accumulatedMap, video) {
var copyOfAccumulatedMap = Object.create(accumulatedMap);
copyOfAccumulatedMap[video.id] = video.title; // <-- My solution
return copyOfAccumulatedMap;
}, {});
} // end of overall function
To verify your solution you click, "Run." If it runs correctly then you get to move on to the next exercise. I did and it gave me the next exercise. My test suite tells me differently.
While trying to solve it, I created this test:
it("should be able to reduce to an object with id's for keys", function() {
var output = [{
"65432445": "The Chamber",
"675465": "Fracture",
"70111470": "Die Hard",
"654356453": "Bad Boys"
}];
expect(exercise19()).toEqual(output);
}); // end it
(I got the output from the tutorial.)
The problem I'm having is the test continues to fail:
Expected [ Object({ 654356453: 'Bad Boys' }) ] to equal [ Object({
65432445: 'The Chamber', 675465: 'Fracture', 70111470: 'Die Hard',
654356453: 'Bad Boys' }) ].
So it seems like it's only picking up the final property, the 'bad boys' property, in the test. I'm thinking that, with the way reduce works and Object.create, that the other properties are there, but they're on the prototype. How can I get this test to pass..?
UPDATE:
I fixed this in a pull-request. These tutorial no uses Object.assign, instead of Object.create. It is now testable. :-)
It looks like a known issue with Jasmine toEqual -- it just ignores properties from prototypes. You probably could use something like that in the test:
// ...
expect(exercise19()).toEqual(jasmine.objectContaining({
"654356453": "Bad Boys"
// rest data here
}));
Object.create creates a new object with the prototype of the object specified in the first argument - you are not copying the object at all, you are creating a new object with Object's prototype - i.e. you're doing a long winded var copyOfAccumulatedMap = {}
instead, do this
return videos.reduce(function(accumulatedMap, video) {
accumulatedMap[video.id] = video.title;
return accumulatedMap;
}, {});