I'm using CoffeeScript from inside Visual Studio with Web Essentials, which provides CoffeeScript support. I just started learning the language and I wonder one thing:
Sometimes I misspell a variable name as follows:
dataUrl = "http://somehost/somepath/somefile.jpg"
dataUrlShort = dataurl.substr(7)
alert dataUrlShort
This will compile fine to
var dataUrl, dataUrlShort;
dataUrl = "http://somehost/somepath/somefile.jpg";
dataUrlShort = dataurl.substr(7);
alert(dataUrlShort);
But the result will be
ReferenceError: dataurl is not defined
This is because I misspelled dataUrl as dataurl on the following line:
dataUrlShort = dataurl.substr(7)
Now, is there a good way to prevent CoffeeScript from using misspelled variable names? In JavaScript, I use JSHint, which allows me to define allowed global variables and throws an error on unknown variable names. This way my life is much easier. Can I do the same with CoffeeScript?
Thanks,
Tommi
Related
I am trying to learn how to implement some of the helper providers: autocomplete, signature help and hover.
I am doing it for a framework that, as far as I know, it cannot be executed outside its main application, so one way I thought to go about this (get the objects types, methods and docs) is by parsing its documentation.
For example the Hover provider; once the cursor is hovering the word, I can search for it in the documentation and display the result:
class HSHoverProvider implements vscode.HoverProvider {
public provideSignatureHelp(
document: vscode.TextDocument,
position: vscode.Position,
token: vscode.CancellationToken
): vscode.SignatureHelp {
// get current word/line under the cursor and find a match inside the docs
...
return new vscode.Hover(data);
}
}
...
context.subscriptions.push(
vscode.languages.registerHoverProvider("lua", new HSHoverProvider())
);
This works fine when the action is directly on the initial declaration. I can parse directly the line and find what I need with a regex.
-- hovering over `application`, I check the context with a regex.
local app = hs.application('Code')
However, I am having a hard time when it comes to a "reference". Searching the document for the declaration of app with a regex approach leads to many edge cases, mainly because of the declaration scope:
Example:
-- declaration target
local app = hs.application('Code')
local function foo()
local app = hs.pasteboard()
end
local function bar()
if 'foo' then
local app = hs.alert()
end
do local app = hs.window.focusedWindow() end
-- a regex will have a hard time to understand which declaration is correct
print(app:title())
end
This lead me thinking that a regex is not the appropriate solution. I also thought that implementing vscode.DefinitionProvider will give me some insight but it did not.
I've tried to look at other extensions that do already the same thing (mainly Lua Language Server by sumneko), but I am not able to understand how they went for it (besides they are using the language server approach).
How would I go for something like this? Do I need an AST tree and inspect from there? Would using the language server be a better choice? Am I missing a bigger picture or I just need a more robust document parser?
Any insight is appreciated. Thanks in advance
The usual approach in such cases is to create a symbol table. You start by parsing the code for which you want to provide the tooling. From the parse tree (or syntax tree, depending on the parser tool used) you generate your symbol table, which holds the informations you need, including the nesting of blocks and symbols, the type of symbols (e.g. object name or object reference) and the scope for which a symbol is valid.
I'm trying to implement clipboardjs into a project and to do so I have the clipboardjs.js file located in ./modules/clipboardjs.js. In the main.coffee file the line require './modules/clipboardjs' is implementing the file. Then I have two twig templates one with a macro initializing the clipboardjs object like so:
<script>
new ClipboardJS('{{ selector }}');
</script>
and the other being the main template file that has all the logic to produce the url. I was having success with a different implementation but now that I'm trying to use the main.coffeescript file to import the js file it's not copying at all. Any thoughts on what I might need to do to get this file loaded properly?
EDIT:
I've tried both solutions by changing the requires statement to ClipboardJS = require './modules/clipboardjs' and window.ClipboardJS = require './modules/clipboardjs'
and both times the errors I'm getting in chrome are:
Uncaught TypeError: Cannot set property 'ClipboardJS' of undefined
at webpackUniversalModuleDefinition (clipboardjs.js:15)
at Module.<anonymous> (clipboardjs.js:7)
at Module../src/scripts/administration/modules/clipboardjs.js (admin.js:190240)
at __webpack_require__ (bootstrap:724)
at fn (bootstrap:101)
at Object../src/scripts/administration/main.coffee (main.coffee:14)
at __webpack_require__ (bootstrap:724)
at fn (bootstrap:101)
at Object.1 (admin.js:192117)
at __webpack_require__ (bootstrap:724)
articles:2332 Uncaught ReferenceError: ClipboardJS is not defined
at articles:2332
(anonymous) # articles:2332
It seems like when I call the ClipboardJS constructor it's not finding the code it needs.
EDIT 2:
#caffeinated.tech I'm not entirely sure, I'm a new dev, but I know they use webpack and gulp. Is there a way to check?
It's probably a problem with scope. In Javascript, a class / variable / function defined at the top level will become globally available in all other scripts in your project.
But in coffeescript, these are scoped within the file, so cannot be used outside the file they are defined in.
You should be able to fix it by assigning the imported ClipboardJS to the global window object (If you are doing any server side rendering, you will have to use global as a fallback to window)
window.ClipboardJS = require './modules/clipboardjs'
Sometimes i have already predefined code and i want functions to autoimport with Quick Fix action is it possible ?
VS Code is conservative when checking JavaScript code. Variables such as beforeSaveWarrior may be a global defined somewhere else (this is a surprisingly common pattern in JavaScript land). This means that using an undefined variable such as beforeSaveWarrior is not considered an error by default.
To show undefined variables as errors and get quick fixes that import them, you need to enable semantic checking in your Js file. The easiest way to to do this is to add // #ts-check at the top of your JavaScript file. Now undefined variables such as beforeSaveWarrior will be marked as errors. The lightbulb for the error should include a fix that adds the import
I'm trying to change some otherwise working code by pulling all the classes into separate files. This works for most classes, except for the part where it reads class window.Timeline. The error message reads ReferenceError: window is not defined
Any suggestions?
It sounds like your file containing that class isn't getting loaded into the window context. Is it possible that it got loaded in the context of another class? Could you post some cod examples in a jsFiddle?
The pattern that I usually follow when exporting coffeescript symbols to the parent context is
exports = exports ? this
class MyClass
someField: false
exports.MyClass = MyClass
If you are using a modern browser and know how to access the debugging console, you could put
console.log this
At the end of the file that is throwing the reference error. This will allow you to have a look to see what the this context is, which may help you troubleshoot.
Working with Rails 3.1 (rc5), and I'm noticing that any coffeescript file I include rails (or sprockets) is adding in initializing javascript at the top and bottom. In other words, a blank .js.coffee file gets outputted looking like this:
(function() {
}).call(this);
This is irritating because it screws up my javascript scope (unless I really don't know what I'm doing). I generally separate all of my javascript classes into separate files and I believe that having that function code wrapping my classes just puts them out of scope from one another. Or, atleast, I can't seem to access them as I am continually getting undefined errors.
Is there a way to override this? It seems like this file in sprockets has to do with adding this code:
https://github.com/sstephenson/sprockets/blob/master/lib/sprockets/jst_processor.rb
I understand that wrapping everything in a function might seem like an added convenience as then nothing is ran until DOM is loaded, but as far as I can tell it just messes up my scope.
Are you intending to put your objects into the global scope? I think CoffeeScript usually wraps code in anonymous functions so that it doesn't accidentally leak variables into the global scope. If there's not a way to turn it off, your best bet would probably be to specifically add anything you want to be in the global scope to the window object:
window.myGlobal = myGlobal;
It seems to be a javascript best practice these days to put code inside a function scope and be explicit about adding objects to the global scope, and it's something I usually see CoffeeScript do automatically.
You don't want to put everything into the global scope. You want a module or module like system where you can namespace things so you don't colide with other libraries. Have a read of
https://github.com/jashkenas/coffee-script/wiki/Easy-modules-with-coffeescript