ESLint shared configuration for all rules within a plugin - javascript

I've created a es lint plugin that provides me with a rule which checks that provided import is not in a dynamic list of blacklisted imports.
The list is loaded from a JSON file.
Currently I am loading this file in the create method of a rule, but the rule is being recreated for each file, which in turn makes the linter slow.
I've found the following text in the ESLint documentation, but no other mention of a way to share some global object within an invocation of the linter.
https://eslint.org/docs/latest/user-guide/configuring/configuration-files#adding-shared-settings
ESLint supports adding shared settings into configuration files.
Plugins use settings to specify information that should be shared across all of its rules. You can add settings object to ESLint
configuration file and it will be supplied to every rule being
executed. This may be useful if you are adding custom rules and want
them to have access to the same information and be easily
configurable.
Is this supported? I've tried exporting a settings object in the index.js of the plugin, but it is not being picked up at all.
module.exports.settings = {
"sharedData": "Hello"
}

Looks like I already have a workaround, but wondering if someone will come up with a better solution.
What I did in the end was to load the configuration in the index of the rule itself, which is loaded at the start of ESLint.
Instead of depending on context.getCwd() I've fallen back to _dirname. Which proved to be enough for my use case.

Related

Calling a function defined outside of the Javascript library

I am working on video.js library. I was trying to modify it, so that it uses a custom player instead of the HTML5 player.
So I replaced the function calls to play() etc with the calls to my custom player(say custFunc1()). These calls are defined in a separate javascript file: custPlayer.js.
So in my index.html file, I will first include the custPlayer.js file and then the built video.js file.
However the problem is that while building the video.js package using grunt, I get the error that custFunc1 is not defined and thus grunt is not able to create the video.js library.
Now I was able to find out from a colleague that adding
/* global custFunc1 */
at the beginning of the particular file in the video.js package from where I was calling custFunc1 resolves the issue. The grunt build succeeds and it works fine.
So what I want to know is:
How does this actually resolve the issue, since this is exactly like a comment in javascript, how does it treat this differently and understand that it indicating that the function definition will be present outside the library?
Is the word global some sort of keyword in javascript?
Are there other ways of achieving this apart from what I mentioned?
On a slightly different note, I wanted to ask if grunt is the rough equivalent of make ?
Your javascript is being linted as part of your grunt process, if you look at the root of your project folder you should see a file like .jshintrc or something along those lines (different depending on the linter).
Your current settings means that the linter is going through your .js files one at a time and if it comes across a variable or function from another files it's throwing the error your seeing. You can either turn off this check or add custFunc1 to an array of known global variables. In jshint you do it like so - https://github.com/gruntjs/grunt-contrib-jshint#jshintrc
{
"globals": {
"custFunc1": true
}
}
The globals will probably already be present in the file, so just add custFunc1: true to it.
Oh and to answer question 1 - the comment type syntax tells the linter to ignore it's settings for that current file, basically overriding the settings in the .jshintrc file.
2 - Yes it's a setting in jshintrc and your adding custFunc1 to it inside the file itself instead of globally in the .jshintrc file.
3 - Mentioned above.
4 - Never used maker but yes i believe its similar in that its a pre process tool

Rule is disabled but not violated

The Story:
We are using ESLint with a set of different plugins. Long ago, in a specific JS-file (page object for Protractor) one of the rules was disabled via a comment at the top of the script:
/* eslint-disable protractor/no-by-xpath */
because there was an xpath() method used that violated the no-by-xpath and at that time we have not found a way to workaround it and we simply disabled the check.
The Problem:
Nowadays, the page object source code changed and there is no xpath() method used anymore. But, the rule is left disabled since the comment disabling it is still there.
The Question:
Our goal is to find the places in the source code where rules are disabled, but not violated. Does ESLint provide anything to report that? How would you approach the problem?
Would appreciate any insights and hints.
No, ESLint doesn't provide anything for this. This feature has been requested a few times, but was deemed unfit for ESLint core. Suggested way of doing something like that would be to create another tool that uses ESLint's Node API, and does two runs on all of the files, once with --no-inline-config flag on, and once with that flag off, then compare results and if files with inline eslint configs don't have any differences, then comments can be removed.

RequireJS, AccountingJs - passing global config into accounting

Im quite new to using requireJs and im having an issue with setting global configuration for a module.
I am using accountingJs and want to modify the setting globally in this case i want to change the symbol from $ to £.
Without RequireJS you would simply do something like this as accounting would be in the global namespace
accounting.settings = $.extend(accounting.settings, {
currency: { symbol: '\u00A3 '}
});
accountingJs is AMD compliant and works perfectly with require but i cant seem to figure out a way of passing the config into it globally rather than .
I have seen the config setting in require docs here and i can set the config here but accountingjs doesn't pick this up (it isnt coded to!).
My question is how can i set configuration like this for a AMD compliant module globally within the page?
I can see a few options
Edit accountingjs to look at module.config() and load any config it sees - i have tried this and it does work as expected but i dont really want a custom.
use shim config and use the init call back - i havent got this to work (maybe because it is already AMD compliant)
create a new module to wrap accountingjs in another define and apply the config here and use this module in each page - not tries this but i guess it would work...
what i really ant to do is have a way of globally applying config to an already existing module from the require config is it possible??
If the AMD module is not designed to use module.config, then you can't force it to use it. The solution you mention last is the most robust: create a wrapper module that configures the actual module as you want. This wrapper can use module.config to grab values. This solution is likely to work with RequireJS now and for quite a long time since you're using API features that are well documented and central to RequireJS' functionality.
As for a shim, I don't recall the docs for RequireJS ever providing a solution that consists as using a shim for a module that is already designed to work with AMD loaders. So if using a shim worked, it would be by happenstance rather than by design.

Dynamically resolve paths with RequireJS

Is there a way to dynamically resolve paths with RequireJS? For example, is it possible to configure it so that, if I do
require(['mymodule'], function(mod){ });
some sort of function of mine will be called, with "mymodule" being passed as a parameter, and with the value I return therefrom being used by Require as the path to use for mymodule?
I do understand that Require has some wonderful convention over configuration with respect to path resolution, and I also understand that paths can be manually configured. But right now I'm trying to add in RequireJS to an old project that was written without Require in mind, so I'm trying to see what all of my options are.
You might be best served by implementing a loader plugin.
Not sure if it's a problem for you, but this would mean your require syntax would turn into something like this:
require(['myplugin!mymodule'], function(mod){ });
The specific method you would use is normalize:
normalize is called to normalize the name used to identify a resource. Some resources could use relative paths, and need to be normalized to the full path. normalize is called with the following arguments:
EDIT: I see there's a replace plugin listed on the plugins wiki which sounds similar to what you are trying to do. It uses only the load method, so apparently what I said above about the normalize method is not a blanket rule.
If the path is truly dynamic, this won't help, but if you just need to modify how the legacy script is returned back to your modules (e.g. taking two different globals and putting them under a different top-level global), you might also think about using the init hook in the shim config option
EDIT 2: some related hacks are posted in this question: Configuring RequireJS to load from multiple CDNs

JavaScript dependency management

I am currently maintaining a large number of JS files and the dependency issue is growing over my head. Right now I have each function in a separate file and I manually maintain a database to work out the dependencies between functions.
This I would like to automate. For instance if I have the function f
Array.prototype.f = function() {};
which is referenced in another function g
MyObject.g = function() {
var a = new Array();
a.f();
};
I want to be able to detect that g is referencing f.
How do I go about this? Where do I start? Do I need to actually write a compiler or can I tweak Spidermonkey for instance? Did anyone else already do this?
Any pointers to get me started is very much appreciated
Thanks
Dok
Whilst you could theoretically write a static analysis tool that detected use of globals defined in other files, such as use of MyObject, you couldn't realistically track usage of prototype extension methods.
JavaScript is a dynamically-typed language so there's no practical way for any tool to know that a, if passed out of the g function, is an Array, and so if f() is called on it there's a dependency. It only gets determined what variables hold what types at run-time, so to find out you'd need an interpreter and you've made yourself a Turing-complete problem.
Not to mention the other dynamic aspects of JavaScript that completely defy static analysis, such as fetching properties by square bracket notation, the dreaded eval, or strings in timeouts or event handler attributes.
I think it's a bit of a non-starter really. You're probably better of tracking dependencies manually, but simplifying it by grouping related functions into modules which will be your basic unit of dependency tracking. OK, you'll pull in a few more functions that you technically need, but hopefully not too much.
It's also a good idea to namespace each module, so it's very clear where each call is going, making it easy to keep the dependencies in control manually (eg. by a // uses: ThisModule, ThatModule comment at the top).
Since extensions of the built-in prototypes are trickier to keep track of, keep them down to a bare minimum. Extending eg. Array to include the ECMAScript Fifth Edition methods (like indexOf) on browsers that don't already have them is a good thing to do as a basic fixup that all scripts will use. Adding completely new arbitrary functionality to existing prototypes is questionable.
Have you tried using a dependency manager like RequireJS or LabJS? I noticed no one's mentioned them in this thread.
From http://requirejs.org/docs/start.html:
Inside of main.js, you can use require() to load any other scripts you
need to run:
require(["helper/util"], function(util) {
//This function is called when scripts/helper/util.js is loaded.
//If util.js calls define(), then this function is not fired until
//util's dependencies have loaded, and the util argument will hold
//the module value for "helper/util".
});
You can nest those dependencies as well, so helper/util can require some other files within itself.
As #bobince already suggested, doing static analysis on a JavaScript program is a close to impossible problem to crack. Google Closure compiler does it to some extent but then it also relies on external help from JSDoc comments.
I had a similar problem of finding the order in which JS files should be concatenated in a previous project, and since there were loads of JS files, manually updating the inclusion order seemed too tedious. Instead, I stuck with certain conventions of what constitutes a dependency for my purposes, and based upon that and using simple regexp :) I was able to generated the correct inclusion order.
The solution used a topological sort algorithm to generate a dependency graph which then listed the files in the order in which they should be included to satisfy all dependencies. Since each file was basically a pseudo-class using MooTools syntax, there were only 3 ways dependencies could be created for my situation.
When a class Extended some other class.
When a class Implemented some other class.
When a class instantiated an object of some other class using the new keyword.
It was a simple, and definitely a broken solution for general purpose usage but it served me well. If you're interested in the solution, you can see the code here - it's in Ruby.
If your dependencies are more complex, then perhaps you could manually list the dependencies in each JS file itself using comments and some homegrown syntax such as:
// requires: Array
// requires: view/TabPanel
// requires: view/TabBar
Then read each JS file, parse out the requires comments, and construct a dependency graph which will give you the inclusion order you need.
It would be nice to have a tool that can automatically detect those dependencies for you and choose how they are loaded. The best solutions today are a bit cruder though. I created a dependency manager for my particular needs that I want to add to the list (Pyramid Dependency Manager). It has some key features which solve some unique use cases.
Handles other files (including inserting html for views...yes, you can separate your views during development)
Combines the files for you in javascript when you are ready for release (no need to install external tools)
Has a generic include for all html pages. You only have to update one file when a dependency gets added, removed, renamed, etc
Some sample code to show how it works during development.
File: dependencyLoader.js
//Set up file dependencies
Pyramid.newDependency({
name: 'standard',
files: [
'standardResources/jquery.1.6.1.min.js'
]
});
Pyramid.newDependency({
name:'lookAndFeel',
files: [
'styles.css',
'customStyles.css',
'applyStyles.js'
]
});
Pyramid.newDependency({
name:'main',
files: [
'createNamespace.js',
'views/buttonView.view', //contains just html code for a jquery.tmpl template
'models/person.js',
'init.js'
],
dependencies: ['standard','lookAndFeel']
});
Html Files
<head>
<script src="standardResources/pyramid-1.0.1.js"></script>
<script src="dependencyLoader.js"></script>
<script type="text/javascript">
Pyramid.load('main');
</script>
</head>
It does require you to maintain a single file to manage dependencies. I am thinking about creating a program that can automatically generate the loader file for you based on includes in the header but since it handles many different types of dependencies, maintaining them in one file might actually be better.
JSAnalyse uses static code analysis to detect dependencies between javascript files:
http://jsanalyse.codeplex.com/
It also allows you to define the allowed dependencies and to ensure it during the build, for instance. Of course, it cannot detect all dependencies because javascript is dynamic interpretet language which is not type-safe, like already mentioned. But it at least makes you aware of your javascript dependency graph and helps you to keep it under control.
I have written a tool to do something like this: http://github.com/damonsmith/js-class-loader
It's most useful if you have a java webapp and you structure your JS code in the java style. If you do that, it can detect all of your code dependencies and bundle them up, with support for both runtime and parse-time dependencies.

Categories

Resources