Confused about how JSHint options work - node.js

Problem
I have made a sample JavaScript file to illustrate my confusion.
(function() { console.log(true == true); })()
This should trip two errors; first the use of == instead of ===, and second, a missing semicolon. However, when I run
var jshint = require('jshint').JSHINT;
jshint('(function() { console.log(true == true); })()');
on in the Node REPL I get errors when I don't expect to. The reason I expect no errors is because in the JSHint documents, it says:
The second parameter [to jshint] is an optional object of options which control
the operation of JSHINT. Most of the options are booleans: They are
all optional and have a default value of false.
I would expect this to produce no errors as I've defined no options so all should be false. The final part of unexpected behavior is that setting options seems to do nothing. The following two calls to jshint also produce the same errors:
var myFile = '(function() { console.log(true == true); })()';
jshint(myFile, {eqeqeq: false, asi: false});
jshint('/*jshint eqeqeq:false, asi:false */\n' + myFile);
Question
I'm not sure how the JSHint options work and I very well may be misinterpreting the documentation. I'd appreciate knowing what in either my invocation of jshint above or in my assumptions is incorrect or if there actually is a problem with JSHint.

Not all options are off by default. In our docs (http://www.jshint.com/docs/) you can see that some options are 'enforcing' and some 'relaxing'[1]. This means that some warnings will be displayed by default and you need to enable 'relaxing' option to turn them off.
Now, with this information, let's look at your second question:
/*jshint eqeqeq:false, asi:false */
(function () { console.log(true == true); })()
This code will trigger an unsafe comparison warning for == true and a missing semicolon. You tried to fix that by turning off two options eqeqeq and asi. The former, when set to true, requires strict comparison everywhere and is turned off by default so you can omit it. You get a warning because JSHint considers == true/false/0/null comparisons unsafe and currently there is no way to turn that off (there won't be warning for a == b for example)[2]. And the latter option (asi) is a relaxing option so you actually need to turn it on to tell JSHint that it's okay to tolerate missing semicolons. So to make your example pass you will need to change it this way:
/*jshint asi:true */
(function () { console.log(true === true); }()
[1] — I understand that this is confusing. Because of backwards compatibility I can't just change how options work but I'm working towards making it less confusing. I will add default values for each option to the docs soon-ish.
[2] — The upcoming 1.0.0 release will allow you to ignore any warnings by their code, even if there's no corresponding named option.

Related

Conditionally import conditionally existing file in Vue

I need to import a file into my project when an environment variable is set, say dist/built.esm.js. It's implied that when the environment variable is set, the file will exist, otherwise it may or may not exist. It seems straightforward to just wrap a call to import in an if statement that checks for the environment variable, but Vue throws the below warning even if the if statement never passes:
And the code:
if (process.env.VUE_APP_USE_COMPILED == 'true') {
const compiledPackage = require('./dist/built.esm.js')
Vue.use(compiledPackage)
}
Setting the if statement to always be false in a nondeterminate way (setting a string var and then comparing it to a different value, instead of just if (false)) results in the same problem, which rules out any possibility of the environment variable being 'true' when it isn't supposed to be.
A temporary workaround I found is to wrap the import in a try/catch, which instead displays a warning instead of an error:
How can I get rid of the errors and warnings completely? I do want it to still error if the file doesn't exist but the environment variable has been set to true, but it shouldn't fail or warn on compilation if the statement hasn't even executed yet.
Does this work?
if (process.env.VUE_APP_USE_COMPILED == 'true') {
import('dist/built.esm.js')
.then(obj => Vue.use(obj))
.catch(err => console.log(err));
}
I managed to figure this out on my own. I used the resolve.alias property in the Webpack configuration to allow a 'soft fail' when the file doesn't exist. I changed my import to use an alias (my-compiled-package-alias), which would conditionally resolve to either the built file or an empty dummy file (dev/import-dummy.js). I had to use resolve.alias rather than resolve.fallback, since Vue2 uses Webpack v4 which doesn't include the latter property.
My updated code:
if (process.env.VUE_APP_USE_COMPILED == 'true') {
const compiledPackage = require('my-compiled-package-alias')
Vue.use(compiledPackage)
}
In my vue.config.js:
module.exports = {
...
configureWebpack: {
resolve: {
alias: {
"my-compiled-package-alias":
process.env.VUE_APP_USE_COMPILED ? "./dist/built.esm.js": "./import-dummy.js"
}
}
},
...
}
but it shouldn't fail or warn on compilation if the statement hasn't even executed yet
Compilation happens before execution. If you get a compile error, that means something went wrong before your code was executed, including any conditionals.
What I believe happens here is that you're using webpack, and it's trying to include dist/built.esm.js in your bundle. Behind the scenes, webpack actually replaces require with some magic. To get around this, use __non_webpack_require__ instead
You could try setting up a compile-time constant using DefinePlugin in your webpack config, maybe something like
plugins: [
new webpack.DefinePlugin({
// this is resolved compile-time
USE_COMPILED: process.env.VUE_APP_USE_COMPILED == 'true'
})
]
Then, in your code
if (USE_COMPILED) require('./dist/built.esm.js')
Here the value of USE_COMPILED should be replaced by webpack compile-time with true if your environment var is set to 'true', and false otherwise.

ESLint no-undef on ES6 function with named arguments

I have a function defined like this:
const generate = (report={}, buffer=false) => {
// do stuff
}
Notice how both of the parameters have default values.
When I call that function and name an argument I get a no-undef ESLint error.
generate(buffer = true);
ESLint says that "buffer" is not defined. It's not detecting that it is a named argument. Does anyone know how to change my .eslintrc to account for named arguments. I can't find anything online.
Thanks in advance!
What you are expecting from this code does not exists in Javascript.
You are getting no-undef ESLint error because buffer is never declared. Since there are no named params in JS, you could just call generate(true).
Although that would actually result in report being equal to true and buffer being settted to its default, which you have setted tofalse.
To achieve something closer to what you are looking for, you could switch the variable orders:
generate(buffer = false, report = {})
And then calling generate(true) would cause a call having the parameters:
buffer = true and report = {}.
Hope that makes sense.
For further reading, I recommend: http://2ality.com/2011/11/keyword-parameters.html

Purescript pulp build output generates requirejs error in browser

When I use pulp build -O -t html/main.js and then pulp build -O -I test -m Test.Main -t html/testmain.js (i.e. building main and test) I get two different js output. In the former case, the format is
// Generated by psc-bundle 0.8.2.0
var PS = { };
(function(exports) {
// Generated by psc version 0.8.2.0
"use strict";
var Prelude = require("../Prelude");
var Control_Monad_Eff = require("../Control.Monad.Eff");
exports["main"] = main;
})(PS["Main"] = PS["Main"] || {});
PS["Main"].main();
Please note the require. In the latter case, the require is not in place at all
// Generated by psc-bundle 0.8.2.0
var PS = { };
(function(exports) {
/* global exports */
"use strict";
exports.concatArray = function (xs) {
return function (ys) {
return xs.concat(ys);
};
};
exports.showNumberImpl = function (n) {
/* jshint bitwise: false */
return n === (n | 0) ? n + ".0" : n.toString();
};
})(PS["Prelude"] = PS["Prelude"] || {});
(function(exports) {
// Generated by psc version 0.8.2.0
"use strict";
var $foreign = PS["Prelude"];
var Semigroupoid = function (compose) {
this.compose = compose;
};
Both examples are shorten, but the point is that require is used in the first time, while not used in the second time.
The issue is that I am not able to run the version using require in the browser due to this error
ReferenceError: require is not defined
When I included require.js into page, I got this error
Error: Module name "../Prelude" has not been loaded yet for context: _. Use require([])
http://requirejs.org/docs/errors.html#notloaded
Thus my question is, what can be done to run the first case in browser.
My guess would be that this comes from running builds with different --require-path options; once with the old default, which was an empty string, and once with ../. This would lead to psc-bundle not realising it needed to include Prelude and Control.Monad.Eff properly in the first case. psc-bundle should replace those require calls with references to the other modules, so that the code works in browsers.
There are a few different ways this can happen, and the compiler has been updated now in a way that should make the probability of this happening again much lower, so I wouldn't spend too much time worrying about exactly how this has occurred.
If none of the above makes any sense to you, don't worry; I think you just need to do the following to fix this:
Update to the latest version of psc (0.8.3 changed the --require-path default to ../, so any version after 0.8.3 should do, but you will want the latest version in most cases)
Delete your output directory
Compile everything again.
You probably need to use the --browserify option to build the first case for the browser.

How do I set default options for traceur.compile and traceur.require?

Using the official traceur module, is it possible to set the default options for compile and require?
For example, this code works:
var traceur = require('traceur');
console.log(
traceur.compile('{ let x = 1; }', { experimental:true }).js
);
Now if I remove traceur.compile's 2nd argument (the options object):
console.log(
traceur.compile('{ let x = 1; }').js
);
Traceur will throw an error as the blockBinding option is not enabled. Is there any way to change the default options, in order to compile files without always passing an options object?
My main concern, apart from applying the DRY principle, is getting the traceur.require function to compile files with customized options -- as far as I can see, traceur.require and traceur.require.makeDefault() do not even take an options argument.
For instance, considering this code sample:
require('traceur').require('./index');
And this piece of code:
require('traceur').require.makeDefault();
require('./index');
Is there any way to compile the required file with the experimental option enabled?
Preferably by altering the default options, as I cannot see any other viable way.
Using Node 0.10.29 and Traceur 0.0.49.
Here's a full example of what I'd like to achieve.
bootstrap.js (entry point):
var traceur = require('traceur');
traceur.options.experimental = true;
traceur.require.makeDefault();
require('./index');
index.js:
import {x} from './lib';
// using a block binding in order to check
// whether this file was compiled with experimental features enabled
{
let y = x;
console.log(y);
}
lib.js:
export var x = (() => {
if (true) {
// should be compiled with experimental features enabled too
let x = 1;
return x;
}
})();
Expected console output: 1
traceur.options.experimental=true serves as a setter which enables the experimental features in the traceur.options object, but unfortunately traceur.options does not seem to affect traceur.compile nor traceur.require as far as I can see.
The Using Traceur with Node.js Wiki page does not mention anything about compiling options. The Options for Compiling page does not mention the Traceur API in Node.js, in fact, I cannot find any documentation about the Traceur API in Node.js.
Fabrício Matté ;-) added support for giving the default options to makeDefault(), see
https://github.com/google/traceur-compiler/blob/master/src/node/require.js#L58
A separate bug with the option experimental was fixed today, 16JUL14.

Using an emscripten compiled C library from node.js

After following instructions on the emscripten wiki I have managed to compile a small C library. This resulted in an a.out.js file.
I was assuming that to use functions from this library (within node.js) something like this would have worked:
var lib = require("./a.out.js");
lib.myFunction('test');
However this fails. Can anyone help or point me to some basic tutorial related to this?
Actually, all the functions are already exported. Generated JavaScript contains following lines:
var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
// …
if (ENVIRONMENT_IS_NODE) {
// …
module['exports'] = Module;
}
If you got a function called my_fun in your C code, then you'll have Module._my_fun defined.
There are some problems with this approach, though.
Optimizer may remove or rename some functions, so always specify them passing -s EXPORTED_FUNCTIONS="['_main','_fun_one','_fun_two']". Function signatures in C++ are bit mangled, so it's wise to extern "C" { … } the ones which you want to export.
Furthermore, such a direct approach requires JS to C type conversions. You may want to hide it by adding yet another API layer in file added attached with --pre-js option:
var Module = {
my_fun: function(some_arg) {
javascript to c conversion goes here;
Module._my_fun(converted_arg) // or with Module.ccall
}
}
Module object will be later enhanced by all the Emscripten-generated goodies, so don't worry that it's defined here, not modified.
Finally, you will surely want to consider Embind which is a mechanism for exposing nice JavaScript APIs provided by Emscripten. (Requires disabling newest fastcomp backend.)
The problem here is that your a.out.js file is going to look like this
function myFunction() {
...
}
Not like this
function myFunction() {
...
}
exports.myFunction = myFunction;
You need to write a build script that lists the tokens you want to publically export from each C program and appends exports.<token> = <token>;\n to the end of your file for each token.

Resources