ESLint rule to detect nested assignments - eslint

There seems to be no ESLint rule to detect nested variable assignments. This is a very common mistake.
function assert (cond) {
if (!cond) {
throw new Error("Assertion failed.");
}
}
function test () {
let var1 = 1;
assert(var1 = 2); // mistake: assigns 2 to var1!
console.log(var1);
}
I tried to propose a new rule at GitHub, but this is only possible when there is a related new ECMAScript feature. And I can't find an existing rule that could be extended accordingly. The no-cond-assign and no-return-assign rules are similar, but they would not be suitable for such an extension.

My question has been answered on GitHub by DMartens and mdjermanovic.
The no-restricted-syntax rule can be used:
e.g.:
"no-restricted-syntax": ["error", {
selector:
"AssignmentExpression:not(
ExpressionStatement > AssignmentExpression,
ForStatement > AssignmentExpression.update )",
message: "Do not nest assignments"
}],
or
"no-restricted-syntax": ["error", {
selector: ":not(ExpressionStatement, ForStatement) > AssignmentExpression",
message: "Do not nest assignments"
}],

Related

Native way of making chrome extension active only in specific URLs

As you can see from the code below, I'm checking the contents of manifest.json to get the matches and exclude_matches in my content_scripts option. I think it works as intended, because I'm seeing the action active only in the URLs listed in "matches" property, not in the ones in "exclude_matches". However, this seems to be too error-prone, because I may have to modify the string replacements in regExpFromMatch if I need to update these match patterns in the future. Is this really making the extension inactive or is it just the action in the toolbar? And, in order to avoid the probable need for repetitive refactoring in the future, I'd like to know if there's a simpler, safer, way to achieve this.
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === "complete") {
const {
content_scripts: [{ matches, exclude_matches }],
} = chrome.runtime.getManifest();
const actionEnabled = isActionEnabledInThisURL(
[matches, exclude_matches],
tab.url
);
if (actionEnabled) {
chrome.action.enable(tabId);
} else {
chrome.action.disable(tabId);
}
// *************************************************************
function isActionEnabledInThisURL(contentMatchPatterns, url) {
const [isMatch, isExcludedMatch] = contentMatchPatterns.map(
(urlMatchPattern) =>
regExpFromMatch(urlMatchPattern).some((regExp) => regExp.test(url))
);
return isMatch && !isExcludedMatch;
}
function regExpFromMatch(matchArray) {
return matchArray.map(
(string) =>
new RegExp(string.replace(/\//g, `\/`).replace(/\*/g, ".*"), "g")
);
}
}
});

Eslint rule is running multiple times

I'm trying to write an eslint rule that enforces making sure the name property is defined on any classes that extend from other Error/Exception named classes (and fixes them).
As far as I can tell, it works in the astexplorer.net individually, but when I'm running it alongside other rules, it ends up getting ran multiple times, so the name property ends up being repeated multiple times in the resulting "fixed" file.
Is there anything in particular I can do to prevent it being run multiple times? I'm assuming what's happening is that it's inserting my name = 'ClassName';, then prettier is needing to reformat the code, which it does, but then maybe it's re-running my rule? I'm not sure.
Rule/fix code shown below. I've tried things like using *fix and yield, but that doesn't seem to help either (see commented code below, based on information in the eslint documentation)
module.exports = {
meta: {
hasSuggestions: true,
type: 'suggestion',
docs: {},
fixable: 'code',
schema: [], // no options,
},
create: function (context) {
return {
ClassDeclaration: function (node) {
const regex = /.*(Error|Exception)$/;
// If the parent/superClass is has "Error" or "Exception" in the name
if (node.superClass && regex.test(node.superClass.name)) {
let name = null;
const className = node.id.name;
// Test class object name
if (!regex.test(className)) {
context.report({
node: node,
message: 'Error extensions must end with "Error" or "Exception".',
});
}
// Find name ClassProperty
node.body.body.some(function (a) {
if (a.type === 'ClassProperty' && a.key.name === 'name') {
name = a.value.value;
return true;
}
});
// Name property is required
if (!name) {
context.report({
node: node,
message: 'Error extensions should have a descriptive name',
fix(fixer) {
return fixer.replaceTextRange(
[node.body.range[0]+1, node.body.range[0]+1],
`name = '${className}';`
);
},
// *fix(fixer) {
// name = className;
// yield fixer.replaceTextRange(
// [node.body.range[0]+1, node.body.range[0]+1],
// `name = '${className}';`
// );
//
// // extend range of the fix to the range of `node.parent`
// yield fixer.insertTextBefore(node.body, '');
// yield fixer.insertTextAfter(node.body, '');
// },
});
}
}
},
};
},
};
Turns out I had the AST Explorer set to the wrong parser, so it was showing me the wrong string name for the ClassProperty node. I should have been using PropertyDefinition instead.

Trying to set a channel and message environment variable globally in a Jenkinsfile but not sure which of two methods are best

Trying to make SEND_SLACK_NOTIF, SLACK_CHANNEL and SLACK_MESSAGE variables and set them as environment variables globally in Jenkins file but I'm not sure which method is superior in a multi-stage pipeline. Don't mind the indenting!
Method 1:
#!/usr/bin/groovy
node('large') {
withEnv(['SEND_SLACK_NOTIF=true',
'SLACK_CHANNEL=UT24K22K1',
"SLACK_MESSAGE=FAILURE: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'\nBetter fix it! (${env.BUILD_URL})"]){
stage('Test') {
if (env.SEND_SLACK_NOTIF) {
slackSend channel: env.SLACK_CHANNEL, color: 'danger', message: env.SLACK_MESSAGE, tokenCredentialId: 'slack-integration-token'
}
}
}
}
Method 2:
#!/usr/bin/groovy
env.SEND_SLACK_NOTIF = true
env.SLACK_CHANNEL = 'UT24K22K1'
env.SLACK_MESSAGE = "FAILURE: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'\nBetter fix it! (${env.BUILD_URL})"
node('large') {
stage('Test') {
if (env.SEND_SLACK_NOTIF) {
slackSend channel: env.SLACK_CHANNEL, color: 'danger', message: env.SLACK_MESSAGE, tokenCredentialId: 'slack-integration-token'
}
}
}
If you just consider your two options, I'd go with option 1 because it's more declarative than option 2. However the superior way is the one described in the Jenkins documentation:
pipeline {
agent {
...
}
environment {
SEND_SLACK_NOTIF = 'true'
SLACK_CHANNEL = 'UT24K22K1'
}
stages {
...
}
}
You might also want to reconsider which variables you really need. If you only use them once, don't use a variable, but use the value directly.

Eslint rule to strict falsy check

Is there a rule for eslint which makes it illegal to write:
if (somevar) { ... }
and enforces you to do proper falsy/truthy checks like
if (somevar === true) { ... }
if (somevar === false) { ... }
if (somevar === undefined) { ... }
ESLint uses static code analysis. As such, it cannot determine the value of a given variable. The following example, would be a problem for a rule like that:
var somevar = 0;
if (somevar) {
...
}
So, no, a rule like that doesn't exist, and would not be possible to create without causing a lot of false positives. (Your example would only apply to booleans, but not to empty objects/string or 0, which is used quite often in the pattern like that).

How to filter urls with # (hash tag) using UrlFilter in a chrome.declarativeContent.PageStateMatcher

I've just started building a chrome extension and as I need to display its icon only for specific urls, I used page_action.
I also used an event listening if the url changes and matches my pattern that way to display the icon:
chrome.declarativeContent.onPageChanged.addRules([
{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlContains: 'https://mysite.com/mypage.html' }
})
],
actions: [ new chrome.declarativeContent.ShowPageAction() ]
}
]);
It works fine but when I want to add a filter of the first character of the query, it fails.
The url pattern I want to filter looks like:
https://mysite.com/mypage.html#e123456789
I tried the following but it didn't help:
pageUrl: { urlContains: 'https://mysite.com/mypage.html#e' }
pageUrl: { urlContains: 'https://mysite.com/mypage.html', queryPrefix: '#e' }
pageUrl: { urlContains: 'https://mysite.com/mypage.html', queryPrefix: 'e' }
I think that the issue comes from the hash tag.
Any idea of a workaround ?
The #... part of a URL is called a "reference fragment" (ocassionally referred to as "hash").
Reference fragments are currently not supported in URLFilters, there is already a bug report for this feature: Issue 84024: targetUrlPatterns and URL search/hash component.
If you really want to show the page action depending on the state of the reference fragment, then you could use the chrome.webNavigation.onReferenceFragmentUpdated event instead of the declarativeContent API. For example (adapted from my answer to How to show Chrome Extension on certain domains?; see that answer for the manifest.json to use for testing):
function onWebNav(details) {
var refIndex = details.url.indexOf('#');
var ref = refIndex >= 0 ? details.url.slice(refIndex+1) : '';
if (ref.indexOf('e') == 0) { // Starts with e? show page action
chrome.pageAction.show(details.tabId);
} else {
chrome.pageAction.hide(details.tabId);
}
}
// Base filter
var filter = {
url: [{
hostEquals: 'example.com'
}]
};
chrome.webNavigation.onCommitted.addListener(onWebNav, filter);
chrome.webNavigation.onHistoryStateUpdated.addListener(onWebNav, filter);
chrome.webNavigation.onReferenceFragmentUpdated.addListener(onWebNav, filter);

Resources