eslint object-shorthand error with variable passed in - javascript

I have the following function that is setting up a select2 plugin, which needs selects to stay open if they are multiple but closed if they are not:
function setUpSelects($selects, closeOnSelect) {
$selects.each((i, item) => {
const $item = $(item);
$item.select2({
closeOnSelect: closeOnSelect, // <-- error on this line
minimumResultsForSearch: Infinity,
placeholder: $item.data('placeholder') || $item.attr('placeholder'),
});
});
}
setUpSelects($('select:not([multiple])'), false);
setUpSelects($('select[multiple]'), true);
However, when I try to run this code, the eslint checker is giving me an error (on the line shown above) of:
error Expected property shorthand object-shorthand
I have done a search and read the docs but it doesn't show how you are meant to use a variable and the unaccepted answer on this question seems to think it may be a bug in eslint (although I have found no evidence to support that)
Is there a way to make this work or should I just disable the rule for that line?

An excerpt from eslint regarding the issue:
Require Object Literal Shorthand Syntax (object-shorthand) - Rule Details
This rule enforces the use of the shorthand syntax. This applies to
all methods (including generators) defined in object literals and any
properties defined where the key name matches name of the assigned
variable.
Change
closeOnSelect: closeOnSelect
to just
closeOnSelect

This rule checks that object literal shorthand syntax is used, e.g {a, b} instead of {a: a, b: b}. The rule is configurable, see options for more details.
Despite this shorthand syntax is convenient, in some cases you may not want to force it usage. You can disable the check in your config:
// .eslintrc.json
{
"rules": {
// Disables the rule. You can just remove it,
// if it is not enabled by a parent config.
"object-shorthand": 0
}
}
In case of TSLint there is a different option:
// tslint.json
{
"rules": {
// Disables the rule. You can just remove it,
// if it is not enabled by a parent config.
"object-literal-shorthand": false
}
}

Wants to define Object with keys and can't use any. Try this.
interface Map {
[key: string]: string | undefined
}
const HUMAN_MAP: Map = {
draft: "Draft",
}
export const human = (str: string) => HUMAN_MAP[str] || str

Related

How to use enum-like javascript-class that assigns its values without constructor

I have this class, which is supposed to represent an enum:
export default class ChangeStatusEnum {
"added" = "added";
"deleted" = "deleted";
"edited" = "edited";
"unedited" = "unedited";
static constructFromObject(object) {
return object;
}
}
It is generated in the pipeline by openapi-generator1 so changing it is not an option. This is not a question on best practices for defining enums in vanilla-js or typescript, this question is about how to use this class.
I do not understand the syntax of assigning to a string, I do not know where these four strings are accessible.
Here are a few things that I have tried (in a jenkins-test so they can be run easily):
test("access", () => {
console.log(ChangeStatusEnum) // prints [class ChangeStatusEnum]
console.log(JSON.stringify(ChangeStatusEnum)) // prints undefined
console.log(
ChangeStatusEnum.constructFromObject("deleted") === "deleted"
) // prints true
console.log(
ChangeStatusEnum.constructFromObject("nonexisting") === "nonexisting"
) // also prints true, which means this syntax has no value over just using strings instead of enums
console.log(ChangeStatusEnum["added"]) // prints undefined
console.log(ChangeStatusEnum.added) // prints undefined
})
The least I expect from a datastructure that calls itself "enum" is that I can construct and compare values of it without fear of silently constructing non-existing values. Iterating over all values of an enum would also be nice, but is not strictly necessary.
I suppose there is a way to do that with this datastructure that I just do not know of due to lack of knowledge of advanced javascript-constructs.
1 The tool is openapi-generator-cli in version 2.5.1 https://www.npmjs.com/package/#openapitools/openapi-generator-cli with openapi-generator-maven-plugin version 6.0.0 https://mvnrepository.com/artifact/org.openapitools/openapi-generator-maven-plugin
Since this is somewhat mature tooling I expect their enum-solution to be usable, this is why I ask this question as a js-question and not as an openapi-question.
I think the most elegant way to use it is to create an instance of it and use it as a constant. The 'constructFromObject'-function is not needed for this. So just put this below the imports:
const changeStatusEnum = new ChangeStatusEnum();
Afterwards, the members can be accessed using normal dot notation:
changeStatusEnum.added // evaluates to the string "added"

Using Closure Compiler on ES6 Modules with Properties

So after a day of testing I'm almost there: using google-closure-compiler-js and gulp.js to minify / compile my ES6 module based "library".
There is just one problem left. How to call the properties of an imported module?
My test case consists of 3 files:
gulpfile.js
const gulp = require("gulp");
const compiler = require("google-closure-compiler-js").gulp();
const sourcemaps = require("gulp-sourcemaps");
gulp.task("default", function() {
// wildcards don't seem to work yet with the js version
// files need to be in reverse order of dependency...
return gulp.src(["src/boilerplate/main.js", "src/app.js"])
.pipe(sourcemaps.init())
.pipe(compiler({
jsOutputFile: "app.min.js",
compilationLevel: "ADVANCED",
warningLevel: "VERBOSE",
createSourceMap: true
}))
.pipe(sourcemaps.write("/"))
.pipe(gulp.dest("./dist"));
});
src/boilerplate/main.js
var mod = {};
export default mod;
var foo = "FOO";
var bar = "BAR";
function foobar(join) {
join = (typeof join === "string") ? join : "";
return foo + join + bar;
}
Object.defineProperty(mod, "foobar", {value: foobar});
src/app.js
import boilerplate from "./boilerplate/main.js";
console.log(boilerplate["foobar"]("+"));
console.log(boilerplate.foobar("+"));
If you log boilerplate here, you see that it has the property "foobar". Symbol intact and all. Great!
Hence app.js' first call – bracket notation ["foobar"] – works perfectly fine. However, the dot notation does not. Calls to an imported module's property get minified by Closure Compiler!
You get your classic "Hi. I'm new to ADVANCED mode" error: TypeError: a.a is not a function.
How do I prevent this? (& let's assume exporting foobar directly isn't viable, for real world's sake.)
Do I need an exports file? How exactly would I do that? My first ventures in that direction did not take me far... is there a trick specific to google-closure-compiler-js?
Is there some kind of hack that allows for dot notation, until Closure Compiler adds a feature that automatically does not rename calls to properties of imports?
And what does this closure-compiler/wiki's article about JS-Modules#type-references advise me to do? Is this the answer I fail to implement?
/** #param {foo.Foo} Foo */
function(Foo) {}
For ADVANCED mode compatibility, use Object.defineProperties to avoid quoted strings.
Object.defineProperties(mod, {
foobar: {value: foobar}
});
Anytime you use quoted strings, you will be required to use brackets (or other techniques) or risk violating the consistent property access rules.

Equivalent of private variable (leading underscore) in es6?

I have this code here:
getData(value, index) {
const {responseMetadata, responseData} = this.getResponseDatum();
return responseData.get(index).get('code').toUpperCase();
}
eslint reports an error:
19:12 "responseMetadata" is defined but never used
In python I can silent this kind of error by renaming the variable to _responseMetadata. Is there a Equivalent in es6?
If you don't need the variable, just don't create it:
const {responseData} = this.getResponseDatum();
A destructuring assignment doesn't need to match all properties of the returned object.
In your case, since you need only one property and don't use it multiple times, there's actually not much reason to use destructuring or a variable at all:
getData(value, index) {
return this.getResponseDatum().responseData.get(index).get('code').toUpperCase();
}
You can turn off a rule for a section of code. See http://eslint.org/docs/user-guide/configuring.html#configuring-rules
/*eslint-disable */
//suppress all warnings between comments
alert('foo');
/*eslint-enable */

Is it safe to declare critical literals in "with (...) {...}" to sandbox code run within it?

I avoid using eval() or Functions created from a string. But when I need to run some subset of Javascript that can be entered by a user I'm tempted to use it just because it will save me much work writing a lexer/parser and interpreter.
Say I'd like to run this code:
a.toLowerCase() === 'xyz' || b == 1 || /pqr/.test(c)
the native approach would be to pass it into eval() like this:
with({a: ..., b: ..., c: ...}) {
ret = eval(code);
}
I cannot be sure that code always contains uncritical code like the above. This opens the possibilities to run malicious code.
I thought of passing an object re-defining critical Browser objects to with besides the actual data like:
var obj = {
// list incomplete ;)
console: true, XMLHttpRequest: true, document: true, window: true, addEventListener: true, removeEventListener: true, parent: true, top: true, history: true, ...,
// actual data
a: ..., b: ..., c: ...
};
with (obj) {
...
}
When running code within with access to the objects/methods is not possibe.
I know that it's still possible to indirectly access those methods if they are indirectly accessed though another object/function that is not re-defined. Let's assume I re-define these too.
Is it secure to sandbox code with a suffient list of objects and functions as content object?
What would be remaining the attack vectors in this case?
Edit 1:
The code should run within Firefox, Chrome, IE (10+), Opera, Safari.
No, this is not secure.
No matter what you do with your code's execution environment using with, it is still possible to retrieve the "real" global object using the following trick:
var window = (function(){ return this }).call(undefined);
This works because Function.call will use the global object as the value of this if it is explicitly passed as undefined or null.
If the shadowed variables were deleted ...
alert([1, window, document]);
var obj = {
document: true, window: true
};
with (obj) {
alert([2, window, document]);
delete window;
delete document;
alert([3, window, document]); //restored
}
Additionally if you exposed any DOM elements the document/window objects could be reached via ownerDocument/defaultView.
You should make use of a global (and "static") function to avoid giving access to other unwanted/private variables (i.e. a sub-function has access to all the variables of the parent function).
Second you want to remove a few keywords from the string to be evaluated to avoid problems as described by duskwuff and Alex K. Something like this:
function exec(e)
{
e = e.replace(/new/, "new_", "g")
.replace(/delete/, "delete_", "g")
.replace(/function/, "function_", "g")
.replace(/throw/, "throw_", "g")
.replace(/this/, "this_", "g")
.replace(/var/, "var_", "g")
.replace(/eval/, "eval_", "g");
obj = { ... };
with(obj)
{
eval(e);
}
}
Note that may not work in strict mode. As mentioned by Bergi in a comment, you could also protect the variables in obj and make them non-deletable so you cannot replace them.
The replace() can include many more things... you may want to look closer at what you are trying to achieve. If the evaluation string is expected to just be an expression, then all keywords should be removed (Except true and false and null). You may also want to remove a few other functions. Here I only removed eval.
If you'd like to only match words so the word anew does not match new you can use the \b flag in the regex. I do not know how compatible this flag is across browsers.
e.replace(/\bnew\b/, "new_", "g");
This would match new but not anew.

is there a way go get typescript to detect when i'm returning undefined from function?

I was hoping that typescript maybe able to detect when a function could return an undefined value and warn me. I tried the following but the playground editor on typescript site did not show any warnings
class Test {
get(key: string) :string{
var hash = {'some-key': 1, 'some-other-key': 3};
return hash[key]
}
}
Is it possible to get typescript to warn when a function could sometimes return a undefined value when you explicitly stated that it should only return some particular type?
TypeScript doesn't check the existence of the property when you use hash[key] as it would when you use hash.myKey. So to get design-time and compile-time checking you would have to change the way you expose this information to allow the code to use the dot-property syntax...
So instead of:
class Test {
get(key: string) :string{
var hash = {'some-key': 1, 'some-other-key': 3};
return hash[key];
}
}
var test = new Test();
test.get('myKey');
You could expose:
class Test {
public hash = { someKey: 1, someOtherKey: 3};
}
var test = new Test();
test.hash.myKey; // you'll get a warning here
This only works if this design is appropriate for what you are doing - but you'll get the warnings doing things this way as TypeScript will create an anonymous type for hash and will ensure only known properties are used.
Update: I updated the examples based on feedback. It is worth noting that although using 'some-key' prevents you from using dot-notation (so it is definitely worth dropping the hyphen if you can) - you will still get code-completion.
It might not stop you from accidentally returning undefined, but your code definitely returns undefined as proven by:
class Test {
get(key: string) :string{
var hash = {'some-key': 1, 'some-other-key': 3};
return hash[key]
}
}
var test = new Test();
alert(test.get("asdf"));
TypeScript would need to support something like CodeContracts to do what you are asking.
As Steve mentioned you can use property access (.) instead of index access ([string]). But that will work only if your properties follow typescript naming conventions. i.e. property names cannot contain '-' e.g. the following works:
class Test {
public hash = {'someKey': 1, 'someOtherKey': 3};
}
var test = new Test();
test.hash.someKey;// Valid
test.hash.myKey; // you'll get a warning here

Categories