Making ESLint work for files which are loaded by others - eslint

I have a set of scripts in which one loads another script file and uses the functions defined in it.
For example, let's say I have main.js script with the following source
load("helper.js");
var stdin = new java.io.BufferedReader( new java.io.InputStreamReader(java.lang.System['in']) );
function readline() {
var line = stdin.readLine();
return line;
}
var N = parseInt(readline());
for(var i = 0; i< N; i++)
{
print("fd630b881935b5d43180ff301525488a");
var num = parseInt(readline());
var ans = perfectNumberCheck(num);
print(ans);
print("dc29e6fa38016b00627b6e52956f3c64");
}
I have another script file, helper.js which has the following source
function perfectNumberCheck(num) {
if(num == 1)
{
return 0;
}
var halfNum = (num/2) + 1;
var sum = 0;
var retVal = 0;
for(var i=1 ; i < halfNum; i++){
if(num % i === 0){
sum = sum + i;
}
}
if(sum == num){
retVal = 1;
}
else {
retVal = 0;
}
return retVal;
}
As it can be seen, main.js uses the function perfectNumberCheck. Now, when I run ESLint on both the files using eslint main.js helper.js or by using eslint *.js, I get the no-unused-vars error 'perfectNumberCheck' is defined but never used even though it is being used in main.js.
I want to keep this error in the configuration but don't want ESLint to show it in such cases.
Is there a way to make ESLint resolve these dependencies without writing the entire code in a single script file?

You can add a comment like /* exported perfectNumberCheck */ to helper.js to tell no-unused-vars that the function is used elsewhere outside that file:
/* exported perfectNumberCheck */
function perfectNumberCheck() {
// ...
}
By itself, ESLint lints each file in isolation, so it will not resolve identifiers defined in other files. The /* exported ... */ comment and globals allow you to inform ESLint of dependencies in other files.
Since exported comments are intended to be used to indicate names that are used elsewhere by being present in the global scope, they have no effect when the file's source in not in the global scope. Specifically, quoting the docs:
Note that /* exported */ has no effect for any of the following:
when the environment is node or commonjs
when parserOptions.sourceType is module
when ecmaFeatures.globalReturn is true

Related

Importing customized module into renderer.js in Electron app

I have a customized module that carries some functions that I would like to use in renderer.js. I tried the following ways of importing but it does not work (in fact, it causes some of the other functions in renderer.js to not execute as well.
const supp = require('./supp.js')
const supp = require('./supp')
const supp = require('supp.js')
const supp = require(path.join(__dirname, '/supp.js')
import 'supp'
supp.js sits in the same folder level as renderer.js and main.js. If someone could advise? Thanks.
Update: below is all the code in file supp.js
const pinOneInGrp = (itemID, grpName, itemColor, grpColor) => {
let item = document.getElementById(itemID);
let grpItems = document.getElementsByClassName(grpName);
for(var i = 0; i < grpItems.length;i++) {
grpItems[i].style.background-color = grpColor
}
item.style.background-color = itemColor;
}
module.exports = {
pinOneInGrp
}
If one of the import or require lines above is included at the top of renderer.js, none of the subsequent actions in renderer.js is executed. For example, there is a ipc.send() and ipc.on() action right after the import / require line. These two do not send (and hence, receive back) from the main.js.
The code you've posted contains a typo. The error it's throwing (which you most probably can't see) is a SyntaxError, because you cannot subtract color (which is undefined) from grpItems[i].style.background and then assign to it. Thus, you simply have to correct your for-loo from
for (var i = 0; i < grpItems.length; i++) {
grpItems[i].style.background-color = grpColor;
}
to
for (var i = 0; i < grpItems.length; i++) {
grpItems[i].style.backgroundColor = grpColor;
}
(And the same goes for the style assignment right below the for-loop!)
Note that all CSS properties which are spelt with a hyphen when in a stylesheet must use camelCase as they otherwise would denote a subtraction, which is causing your problems. Also, this behaviour is explained in Mozilla's Developer Network Web API reference, specifically under "Setting styles".

How to get known Windows folder path with Node

I need to access per-machine configuration data in my Node application running on Windows. I've found this documentation for how to find the location:
Where Should I Store my Data and Configuration Files if I Target Multiple OS Versions?
So, in my case, I would like to get the path for CSIDL_COMMON_APPDATA (or FOLDERID_ProgramData). However, the examples are all in C, and I would prefer to not have to write a C extension for this.
Is there any other way to access these paths from Node, or should I just hardcode them?
After doing a bit of research, I've found that it's possible to call the relevant Windows API proc. (SHGetKnownFolderPath) to get these folder locations, see docs at: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762188(v=vs.85).aspx.
We call the APi using the FFI npm module: https://www.npmjs.com/package/ffi.
It is possible to find the GUIDs for any known folder here:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx
Here is a script that finds the location of several common folders,
some of the code is a little hacky, but is easily cleaned up.
const ffi = require('ffi');
const ref = require('ref');
const shell32 = new ffi.Library('Shell32', {
SHGetKnownFolderPath: ['int', [ ref.refType('void'), 'int', ref.refType('void'), ref.refType(ref.refType("char"))]]
});
function parseGUID(guidStr) {
var fields = guidStr.split('-');
var a1 = [];
for(var i = 0; i < fields.length; i++) {
var a2 = [...Buffer.from(fields[i], 'hex')];
if (i < 3) a2 = a2.reverse();
a1 = a1.concat(a2);
}
return new Buffer(a1);
}
function getWindowsKnownFolderPath(pathGUID) {
let guidPtr = parseGUID(pathGUID);
guidPtr.type = ref.types.void;
let pathPtr = ref.alloc(ref.refType(ref.refType("void")));
let status = shell32.SHGetKnownFolderPath(guidPtr, 0, ref.NULL, pathPtr);
if (status !== 0) {
return "Error occurred getting path: " + status;
}
let pathStr = ref.readPointer(pathPtr, 0, 200);
return pathStr.toString('ucs2').substring(0, (pathStr.indexOf('\0\0') + 1)/2);
}
// See this link for a complete list: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx
const WindowsKnownFolders = {
ProgramData: "62AB5D82-FDC1-4DC3-A9DD-070D1D495D97",
Windows: "F38BF404-1D43-42F2-9305-67DE0B28FC23",
ProgramFiles: "905E63B6-C1BF-494E-B29C-65B732D3D21A",
Documents: "FDD39AD0-238F-46AF-ADB4-6C85480369C7"
}
// Enumerate common folders.
for(let [k,v] of Object.entries(WindowsKnownFolders)) {
console.log(`${k}: `, getWindowsKnownFolderPath(v));
}

How to include a static mapping file as part of a nodeJS module?

Assume that I have a nodeJS module whose index.js is as below
module.exports = function() {
var map = {},
CSV_FILE = "./input.csv",
_loadCSV = function() {
var fs = require('fs'),
parse = require('csv-parse'),
rawCSVData = fs.readFileSync(CSV_FILE).toString(),
i,
item;
parse(rawCSVData, {columns: true}, function(err, data) {
for (i = 0; i < data.length; i++) {
item = data[i];
map[item.key] = item.value;
}
});
},
_init = function() {
_loadCSV();
};
// Init
_init();
// Public
return {
/**
* getValue
*/
getValue: function(key) {
return map[key];
}
};
};
Now, everything works fine if I test locally. However, when I install this module in another project I get below error.
fs.js:549 return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
^
Error: ENOENT: no such file or directory, open 'input.csv' at Error (native)
Is it possible to include a static mapping file as part of a nodeJS module that is used in module initialization?
Your problem is this line CSV_FILE = "./input.csv". It works locally because the script you're executing (index.js) is in the same directory as the input.csv-file. However, when you install it as a dependency, the input.csv-file is actually somewhere in ./node_modules/your-module/input.csv, hence your new index.js can't see any ./input.csv-file since it's not located in the same directory as the calling script.
There are two ways to solve this, the first one being the smartest in my opinion.
Do not distribute the input.csv-file. This is a very bad approach to building modules, and you should rather change your code so that your module accepts a path to a .csv-file that it loads. However your module may need static data, but in those cases it's smarter to just convert it to a JavaScript Object and include it directly.
Simply change one line of code,
from CSV_FILE = "./input.csv"
to CSV_FILE = __dirname + "/input.csv"
See documentation for __dirname

Sort TypeScript files by dependencies in NodeJS

I have some files and some of them have dependencies some of them dont.
There are also cicle dependencies. I want to sort this files by this dependencies to concat the files later in the correct order.
This are TypeScript files, but I collect all files in a NodeJS program where I want to sort the TypeScript files.
Example (This are only random names):
There are two options here, the first is basically "you don't need to" and the other is use a tool to put Humpty Dumpty together.
Node will handle require for you if you use commonjs as your module arg when compiling your TypeScript, then when running Node will load the dependencies for you at runtime
You can concat/bundle your output with with tools like webpack/browserify which will analyze your dependencies and put the files/contents in the right order in a single output file
Thanks for some answers of things that I already knew, I found a correct answer by myself, here is my solution:
var stack = [];
var visited = [];
function topologicalSortUtil(item) {
visited.push(item.fullPath);
for (var i = 0; i <= item.dependencies.length - 1; i++) {
var dependency = item.dependencies[i];
if (visited.indexOf(dependency.fullPath) !== -1) {
continue;
}
topologicalSortUtil(dependency);
}
stack.push(item);
}
function topologicalSort(data) {
for (var i = 0; i <= data.length - 1; i++) {
var item = data[i];
if (visited.indexOf(item.fullPath) !== -1) {
continue;
}
topologicalSortUtil(item);
}
return stack;
}
DEMO
References:
https://en.wikipedia.org/wiki/Topological_sorting
https://www.youtube.com/watch?v=ddTC4Zovtbc
https://github.com/mission-peace/interview/blob/master/src/com/interview/graph/TopologicalSort.java
You can place reference tags at the top of each file, and use the --out CLI option. TSC will figure out the rest. Circular dependencies won't break TSC, but you do need to take into account that something may not exist yet at runtime.
Shape.ts
/// <reference path="Test.ts"/>
Test.ts
/// <reference path="Vector.ts"/>
Vector.ts
/// <reference path="Group.ts"/>
/// <reference path="Shape.ts"/>

Multiple requires of same module seem to affect scope of each successive require

I created the following 3 files:
base.js
var base = {};
base.one = 1;
base.two = 2;
base.three = 3;
base.bar = function(){
console.log( this.three );
};
a.js
var base = require('./base');
base.three = 6;
module.exports = base;
b.js
var base = require('./base');
module.exports = base;
test.js
var test_modules = ['a','b'];
test_modules.forEach( function( module_name ){
require( './' + module_name ).bar();
});
And then run test.js like so:
node ./test.js
It outputs this:
6
6
Why is it that when I set the property 'three' of module 'base' in 'a.js', it then affects the object in 'b.js'?
When you require() a module, it is evaluated once and cached so that subsequent require()s for the same module do not have to get loaded from disk and thus get the same exported object. So when you mutate exported properties, all references to that module will see the updated value.
You are introducing global state for base module.
The module a mutated base and then exported it as well, which means that any further references to base will have an updated value.
It is best demonstrated by the following script inside test.js
var testModules = ['b', 'a'];
testModules.forEach(function(module) {
require('./' + module).bar();
});
Now when you run node test.js, you'll see
3
6
Why?
Because the order of inclusion of the modules changed.
How do I solve this?
Simple, get rid of global state. One option is to use prototypes like so
var Base = function() {
this.one = 1;
this.two = 2;
this.three = 3;
};
Base.prototype.bar = function() {
console.log(this.three);
};
module.exports = Base;
And then, inside a.js
var Base = require('./base');
var baseInstance = new Base();
baseInstance.three = 6;
module.exports = baseInstance;
And inside b.js
var Base = require('./base');
module.exports = new Base();
Now when you run your original test.js, the output should be
6
3

Resources