CodeMirror - get linting result from outside of the editor - javascript

I'm using the CodeMirror library which is awesome. The code editor that I'm istantiating is a part of a form and therefore I want to do a basic check with linting to see whether the user's input seems valid. Unless the code is fine, I don't want to process the form.
So the question is: is there a method on the CodeMirror editor instance that would allow me to retrieve the result of linting? I'm looking through the docs and Google but failed to find anything helpful. There's this performLint method that is added to the editor, however it does not return the results of linting.

There isn't a specific method to get the linting results, but there is a hook provided when you define a getAnnotations property in the lint options object.
Here's a basic options object that would trigger linting:
var codeMirrorOptions = {
"lineNumbers": true,
"indentWithTabs": true,
"mode": "css",
"gutters": ['CodeMirror-lint-markers'],
"lint": true
}
You can specify an object (instead of a boolean) as the lint property:
"lint": {
"getAnnotations": css_validator,
"async": true
}
Then, define your own validator function. This function can just call CodeMirror's bundled validator:
function css_validator(cm, updateLinting, options) {
// call the built in css linter from addon/lint/css-lint.js
var errors = CodeMirror.lint.css(cm);
updateLinting(errors);
}
At this point you've replicated the behavior of lint:true -- but now the errors variable contains an array of lint errors. If errors.length == 0, no errors were found.
Note: this sample assumes you are linting CSS, but the same would apply for other types.

The updateLinting function in lint.js passes its annotations (and editor) to the onUpdateLinting option:
if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
so all you have to do is have your handler as the lint option property:
lint: { onUpdateLinting: handleErrors }

This is a hint for Dezzas Answer:
Write,
var errors = CodeMirror.lint.css(cm, options);
Otherwise, it will fail.

#Clem's answer led me in the right direction, though I did run into a few issues. The first was seeing Bad option: onUpdateLinting repeatedly in the console (See this reported Codemirror issue). The second was seeing the annotations array containing null entries sometimes. Here is my linting configuration passed into Codemirror that solves these issues. Note that I'm using react-codemirror2, but the options get passed into Codemirror in the same format. My component has an optional onLintingComplete callback that can be provided by the consuming component and you'll see that callback referenced below where it is passed the array of lint annotations:
lint: onLintingComplete
? {
onUpdateLinting: (_annotationsNotSorted, annotations) =>
onLintingComplete(
// sometimes codemirror includes null annotations in the array, so we want to filter these out
annotations.filter(annotation => annotation != null)
),
// This empty lint options object is needed here, see: https://github.com/codemirror/CodeMirror/issues/4198
options: {},
}
: true,

Related

Use 'strictNullChecks' annotation on one function/method

I have this method:
remove(node: SortedQueueNode<V, K>) : SortedQueueNode<V, K>{
// ...
return node.parent;
}
there are multiple return statements in the function body, and I want to avoid null/undefined return statements. Is there an annotation I can add to just this method, something like:
// #ts-strictNullChecks
remove(node: SortedQueueNode<V, K>) : SortedQueueNode<V, K>{
// ...
return node.parent;
}
As of TypeScript 4.9 the --strictXXX compiler options are each either enabled or disabled; there is no support for applying them at a more granular or modular level.
But, at microsoft/TypeScript#49886 there is an implementation of per-file compiler options, where some compiler options including --strictNullChecks can be enabled or disabled for an individual file in a project. As of today this has not been merged into the main branch, but it is part of the TypeScript 5.0 iteration plan at microsoft/TypeScript#51362, so there's a good possibility that it will be released with TypeScript 5.0. Until and unless it is released, I think you're stuck.
If and when it is released, it wouldn't be exactly the same as a function-scoped compiler option. But you could get a similar effect to by refactoring your code so that the parts you want to check differently live in different files, such as:
// someFile.ts
// #ts-strictNullChecks true
// -------------------> ^^^^ change to false to see error go away
Foo.prototype.remove = function <V, K>(node: SortedQueueNode<V, K>) { // error!
//~~~~~~~~~~~~~~~~~~ <-- undefined is not assignable to SortedQueueNode<V, K>
return node.parent;
}
where the //#ts-strictNullChecks true compiler directive causes the whole file to be checked strictly for null/undefined-related errors, and where your remove() method is implemented in this file separately from the rest of the class.
You can see this in action now, by using the 4.9.0-pr-49886-38 version of TypeScript: Playground link to code, 4.9.0-pr-49886-38

ESLint prefer-arrow-functions not flagging correctly

Currently working on an .eslintrc file and I have implemented this so far
"prefer-arrow/prefer-arrow-functions": [
"warn",
{
"disallowPrototype": false,
"singleReturnOnly": true,
"classPropertiesAllowed": false,
"allowStandaloneDeclarations": true
}
],
const a = activeABTests.reduce(function(accumulator: number, abtest: ABTestFunnelType): number {
I want this function above ^ to flag. It is not warning me in the Github check. It should flag and ask to be converted to an arrow function that looks like this:
const a = activeABTests.reduce((accumulator: number, abtest: ABTestFunnelType) => number {
I don't want to flag functions like this. I think the allowStandaloneDeclarations was the fix, but I am not sure.
I am getting two types of warnings:
Warning: 105:36 warning Prefer using arrow functions over plain functions prefer-arrow/prefer-arrow-functions
Warning: 31:5 warning Use const or class constructors instead of named functions prefer-arrow/prefer-arrow-functions
What can I do to make sure that the right functions are being flagged? I'm currently getting a ton of warnings but want to eliminate them/make sure they are the right ones.

Moving folders using gulp

I have project with 3 folders (I'm using gulp), which I don't need to compile. So, I need a task, which takes 3 folders "src/fonts", "src/libs" and "src/docs" as gulp.src() and just move them in dest/ folder. I don't need to do something with them, just move them after building.
My current attempt:
gulp.task('others', function () {
return gulp.src(['src/libs/**'], ['src/fonts/**'], ['src/docs/**'])
.pipe(gulp.dest('dist/'))
});
Using this code, task move only inner files and folders(need to be wrapped), and it take only "src/libs" as gulp.src()
Problem:
You're using gulp.src() wrong.
Explanation:
In the current state of your code, the following is happening:
['src/libs/**'] gets passed to globs property
['src/fonts/**'] gets passed to options property
['src/docs/**'] gets passed to NOTHING
The above explains why you're only seeing the files of src/libs being selected.
Thus:
gulp.src(['src/libs/**'], ['src/fonts/**'], ['src/docs/**'])
should be
gulp.src(['src/libs/**','src/fonts/**','src/docs/**'])
or (with a file wildcard *.*)
// something like this (its dirty as I'm writing this off the cuff)
// but you get the idea
var sources = [
'src/libs/**',
'src/libs/**/*.*',
...
];
gulp.src(sources)
Some More Information:
The docs specify the usage as such:
gulp.src(globs[, options])
where globs can only be a:
string => 'im/a/single/directory/or/file/s'
(a single) array object => ['dir1','dir2','dir3','etc']
and options, ... well, an options object (with defined values that you can supply)
options => { buffer: true, read: false, ... }

Tern Fails to use JSDoc Type Information

I'm trying to use Tern to perform type inference on some Javascript code. However, the type inference doesn't seem to be using the JSDoc comments alongside the code.
I'm using the code /** #type {Foo} */ let x; as an example of the problem. On the Tern website's demo page (which uses CodeMirror), the editor is able to infer that the type of x is Foo.
Yet, when run locally via node, I get this back: { type: '?', exprName: 'x' }.
Here's a snippet that replicates the issue:
const tern = require('tern');
const ternServer = new tern.Server({
plugins: {
doc_comment: {
strong: true
}
}
});
const js = `/** #type {Foo} */ let x;`;
ternServer.addFile("main", js);
ternServer.request({
query: {
type: "type",
file: "main",
start: js.length - 2,
end: js.length - 2
}
}, console.log);
Tern has otherwise been working perfectly fine for type inference. It's when using the JSDoc comments that it doesn't seem to work with the way I've initialized and called it.
I even set the doc_comment plugin to strong, which means that JSDoc types are preferred over normally inferred types, but to no avail.
Any ideas how to get this to work?
As it turns out, you have to import the doc_comment plugin in order to use it. Otherwise, setting the plugins option for the tern server won't do anything.
Simply adding require("tern/plugin/doc_comment"); to the top of the file solved the problem.

Adding to ace-editor wise autocomplete: List user-defined functions and variables (javascript language)

I want to add list of user-defined functions and variables to ace editor's auto-complete.
To do it I want to examine all the code user inserted to the document, find defined functions (and their arguments), defined variables and their scope, etc.
Main question
Is that data already calculated somewhere in the ace source-code (or language-plugin) and I can just grab it in a way?`
What I want
for exapmle, if user inserted code like this:
var var0 = 'abcd';
function foo(var1, var2){
var var3 = 'efg';
}
I want to add to the auto-complete box, function called 'foo' with two parameters - var1 and var2. I want to add also var0 to variables list, and to add var3 just when user writes in the scope it's defined (in the function).
What I already knows :
I know how to enable auto-complete and live auto-complete.
I know how to add new completer
I know that built-in Basic auto-complete adding all the words in document Indiscriminately
I know about ace-tern plugin, and I don't think I want to use it. For now it's still hackish, documention-less, and I can't figure how to enable it.
I know that Ace already have some of the data I'm after. For example it warns when a variable is re-defined when already defined in the same scope. So it had list of variables and their scope. My guess it's using jshint - but Is there a way to grab it from there?
I read ace documation and find a lot useful methods I can use to extract the data, if I have to. The question is if I really need to do this myself.
UPDATE: I implied that in my answer, but to clarify - Tern will do exactly what you are asking in what i want. Snippet below solves one more problem of providing some context which you do not want user even see in the editor. See screenshots of your code used at Ace.Tern live demo
That is opionated,but imo the best option for adding auto-complete in ace is Tern.
Tern accepts typedef configuration option ( described here: http://ternjs.net/doc/manual.html#typedef), but what is more interesting, it will accept your custom js object as a child, ie:
var myContext = {
name: 'myContext',
obj: obj
}
Where obj is your js object. Then in Tern configuration you will use it as:
defs: ['underscore', myContext]
Which will use both your custom object and underscore module for autocomplete.
Tern related ace.js config: (See https://github.com/sevin7676/Ace.Tern/blob/master/demo.html for comments on config options)
var myContext = { ... }
var editor = ace.edit("editor");
editor.getSession().setUseWorker(true);
ace.config.loadModule('ace/ext/tern', function () {
editor.setOptions({
enableTern: {
defs: ['browser', 'ecma5', myContext],
plugins: {
doc_comment: {
fullDocs: true
}
},
useWorker: true,
startedCb: function () {
console.log('editor.ternServer:', editor.ternServer);
},
},
enableSnippets: true,
enableBasicAutocompletion: true,
});
});

Categories