Kontrola JavaScriptu s JSLint a JSHint

V článku si představíme dva podobné nástroje, které vám mohou ušetřit čas při programování statickou kontrolou kódu v JavaScriptu. Zkontrolují, zda dodržujete jednotná pravidla zápisu kódu a upozorní vás na případné syntaktické chyby, překlepy, ale i na „zapomenuté“ příkazy, proměnné či nejasné konstrukce.
Seriál: Javascriptaření (9 dílů)
- Javascriptaření: hrajte si s funkcemi! 31. 1. 2011
- ECMAScript Strict mode ve Firefoxu 4 8. 2. 2011
- Javascriptaření: nejen jQuery živ je JavaScriptař 8. 3. 2011
- Javascriptaření: fyzika, grafika a společenská konverzace 23. 3. 2011
- JavaScriptaření: drátujeme, překládáme, spojujeme 31. 3. 2011
- Javascriptaření: ukažte mi, označte mě, opravte mě 13. 4. 2011
- Kontrola JavaScriptu s JSLint a JSHint 14. 7. 2011
- Základní vzory pro vytváření jmenných prostorů v JavaScriptu 10. 10. 2011
- Javascriptaření: překladače, pakovače 9. 11. 2011
Nálepky:
JSLint
JSLint je nástroj pro kontrolu kvality kódu. Jeho autorem je známý vývojář a propagátor Douglas Crockford (bude hostem na letošním WebExpo – pozn.red.). Nástroj JSLint provede statickou analýzu a upozorní na místa, která by mohla způsobit problémy. Používání JSLintu nutí programátora dodržovat určité konvence. Výsledkem je kód, u něhož je konzistentní coding standard, což pomáhá eliminovat mnohé zásadní chyby.
Abychom si udělali lepší představu o tom, co JSLint dokáže, přejdeme rovnou k jednoduchému příkladu. Představme si, že náš zdrojový kód obsahuje mimo jiné tuto podmínku (s „chybou“):
if (a = b) { // nejaky korektni kod }
Bystrý čtenář si povšimne, že došlo zřejmě k chybě z nepozornosti či k překlepu a proměnné se v podmínce neporovnají, ale přiřazují. JSLint v takovém případě vypíše pozici chyby a zprávu:
Expected a conditional expression and instead saw an assignment.
Instalace a použití
JSLint existuje jako online nástroj (JSLint online), ale lze jej použít i offline. Stáhněte si aktuální verzi z GitHubu:
git clone https://github.com/douglascrockford/JSLint
V aktuálním adresáři se vytvoří adresář se staženým projektem. Hlavní soubor, který nás zajímá, je jslint.js
. V něm se nachází globální funkce JSLINT. Použití s implicitním nastavením je snadné:
var myResult = JSLINT(source, options);
V proměnné source
se nachází řetězec s kódem určeným ke kontrole. V myResult bude hodnota true
, pokud byl kód podle JSLint správný, jinak false
. V globálně dostupném poli JSLINT.errors budou pak jednotlivé chyby, vždy s číslem řádku, popisem problému a dalšími informacemi.
Druhý parametr je volitelný parametr, který obsahuje nastavení pravidel.
Používáte-li nějaký specializovaný editor, může být JSLint dostupný jako plugin. Některé pluginy do editorů mohou mít ale jiné nastavení, např. plugin pro VIM nevyžaduje mezeru za ‚if‘ a naopak chce středník za každým příkazem.
Podívejme se teď na část pravidel, které JSLint obsahuje. A nezapomeňte na autorovo varování: JSLint will hurt your feelings.
Typová kontrola
var i = 0; i = "a";
Type confusion: 'i': number and 'a': string.
Přestože JavaScript není staticky typovaný jazyk, JSLint dokáže v tomto případě rozpoznat, že jste do číselné proměnné chtěli uložit řetězec.
Operace inkrementace a dekrementace
Tyto operace jsou zakázány, neboť bývají zdrojem záludných chyb. Jsou povolené jen v cyklu for.
Vytváření objektů
var a = new Object();
Use the object literal notation {}.
JSLint vyžaduje specifický zápis pro nové objekty. Proč nám nutí jinou notaci, když je to „to samé“? Důvody jsou následující:
- syntaxe je mnohem kratší
- elegantněji se vytvářejí objekty za běhu:
{name: "Bob", age: 8}
Povinné středníky
var foo = function () { //... }
Středníky jsou v JavaScriptu nepovinné (resp. existují poměrně komplikovaná pravidla, která říkají, kde si má interpret středník „domyslet“). Výsledkem je, že pokud k předchozímu kódu připíšete něco takového:
(function () { //... })();
bude celý kód interpretován jako
var foo = function () { //... }(function () { //... })();
Druhá funkce se stane parametrem pro volání té první, a výsledek se bude volat jako funkce. Tedy něco jiného, než jsme zamýšleli. Proto JSLint na střednících trvá.
Eval je zlo
Přiznejme si, že spouštět kód v řetězci není úplně nejčistší řešení. Kód v řetězci není vizuálně strukturovaný, editory běžně nezvýrazňují syntax JavaScriptu v řetězcích, a to ani nemluvíme o možných bezpečnostních rizicích, spojených s neošetřeným vstupem funkce eval().
Nedosažitelný kód
JSLint kontroluje, zda za příkazy jako return
, které „odkloní“ běh programu, není nějaký další kód. Pokud je, upozorní na to.
JSLint dovede uživatele zahltit slušnou řádkou zpráv i při poměrně banální chybě. Vyplatí se nejdřív podívat na daný řádek a zamyslet se, co je špatně, než mechanicky chybu po chybě napravovat.
Některá varování JSLint mohou být až nesmyslná a mohou vás pěkně vytočit. Dejte ale Douglasovi šanci a najděte si, co to varování znamená – většinou má nějaký smysl. Pokud vám ale některá varování opravdu nevyhovují a považujete je v dané situaci (nebo obecně) za nesmyslná, můžete některá z nich potlačit v konfiguraci.
Závěrem: JSLint nám dává možnost zamyslet se nad způsobem, jakým píšeme v JavaScriptu, a nad návrhem jazyka ECMAScript jako takového.
JSHint
Jestliže se vám zdá JSLint příliš radikální a omezujíci, JSHint by mohlo být to pravé. Jeho autory rozčiloval fakt, že JSLint nutil programátory psát jako Douglas Crockford. Proto vznikl fork z verze 2010–12–16. Ten je méně pedantický a dostal jméno JSHint. Jeho vývoj je řízený komunitou a klade důraz především na respektování odlišných programovacích stylů. Je možné nastavit kontrolu každého pravidla, které chceme dodržovat.
git clone https://github.com/jshint/jshint.git
Použití offline verze je stejné jako u JSLint, jen se používá funkce JSHINT.
Konstrukce, které JSLint zakazoval, je možné v JSHint povolit. Například operátor přiřazení v podmínce, podmínka bez složených závorek, funkce eval… Navíc je u JSHint možné specifikovat i prostředí (prohlížeč, jQuery/Prototype atd.), které používáme. JSHint tak rozpozná příslušné globální proměnné a nehlásí „planý poplach“.
Jako materiál pro článek byla použita JSLint edice 2011–07–01, JSHint edice 2011–04–16, Ubuntu 11.04.
- http://www.jameswiseman.com/blog/2011/01/19/jslint-messages-use-the-object-literal-notation/
- http://stackoverflow.com/questions/444080/do-you-recommend-using-semicolons-after-every-statement-in-javascripto
- http://anton.kovalyov.net/2011/02/20/why-i-forked-jslint-to-jshint/
- http://zdrojak.root.cz/zpravicky/staticka-kontrola-javascriptu-zeon-js/
- http://zdrojak.root.cz/zpravicky/javascript-doctor-vyzna-se-i-ve-vasem-kodu/
- http://zdrojak.root.cz/zpravicky/jshint-novy-kontroler-syntakticke-spravnosti-javascriptu/
Dovolím si přihodit odkaz na návod, jak spustit takovou validaci z příkazové řádky, třeba v rámci continuous integration: http://www.tomas-dvorak.cz/clanky/jshint-a-spousteni-validace-javascriptu-z-prikazove-radky . Třeba to někomu pomůže zaintegrovat do vývojového procesu.
Tahat kvoli tomuto JRE na server mi nepride ako najlepsi napad. Predpokladam, ze navod vznikol este v dobe, ked nebol v kurze Node.js, ktory sa predsalen hodi na server viac.
Nn, naopak sem nemel potrebu pouzivat node.js kdyz jre pouzivam pro kvanta jinych veci v ramci CI. Navic cely projekt nam bezi na jave, proste ji mame vsude :) Ale pokud nekdo nalinkujete implementaci pro debian v node.js, rad se priucim ;)
Uh, reagoval som prehnane rychlo a nedoslo mi, ze aj serverove aplikacie sa pisu v Jave. Dopleteny zo vsetkych tych dynamickych jazykov.
No tak jsem zkusil prohnat výsledek z CoffeScriptu přes JSLint a JSHint na vzorový kód „square = (x) -> x * x“
Přes JSHint prošel ok, ale JSLint opravdu hází věci typu:
– Expected exactly one space between ‚function‘ and ‚(‚.“
– Expected ‚return‘ at column 5, not column 3.
Bližší mi zůstane asi JSHint
JavaSlint :-D
Autor JSLintu o svém „čístém“ JavaScriptu, který ten program vynucuje, napsal dokonce celou knihu, jmenuje se to JavaScript: The Good Parts. Myslím v článku o tom zmínka není.
Jinak, tenhle přístup má asi něco do sebe, například v Google Go se projevuje v podobě nástroje gofmt, což je automatický formátovač kódu, jazyk tím má definovaný „jediný správný“ způsob odsazování atd.
Za zminku urcite stoji i Zeon.js (zeonjs.com). Je to kompletne v JavaScriptu napsany parser, generuje AST a provadi nad nim analyzu kodu. Velice pokrocily nastroj. Dokaze provadet analyzu real-time pri psani kodu. Reparsuje kod po kazde zmene pritom odezva je okamzita.
ako kontrolovat cez JSLint kod, ked je rozdeleny do viacerych zdrojovych suborov?
iterovat pres vsechny *.js soubory a nad kazdym z nich spustit kontrolu?
problem je, ze pri kontrole JSLint napise, ze nepozna nejaku funkciu, ale ta je pritom dostupna v dalsom subore…
jedine riesenie zatial vidim v docasnom zluceni vsetkych suborov kvoli kontrole… (prip. v ignorovani takych chybovych hlaseni)
Díky za tip na JSHint, JSLint jsem přestal používat proto, že autor do něj začal cpát svoje představy o jediném správném zápisu kódu a znechutilo mě prodírat se kupou nepodstatných hlášek, jako „Expected exactly one space between ‚)‘ and ‚event'“.
if (a = b)
{
…
}
ale ono to neni chyba proste priradím do premennej „a“ hodnotu premnnej „b“ a premennú „a“ potom testujem či má hodnotu true
Ano, máte pravdu. Proto jsem slovo ‚chyba‘ dal do uvozovek, aby se to nebralo doslova.
Zato je to krasne krypticky kod, az pak budete hledat chybu, takovy zapis v pohode prehlednete. Proto se pred tim obecne varuje ;)
Netvrdím, že používať eval je správne, ale argument „a to ani nemluvíme o možných bezpečnostních rizicích, spojených s neošetřeným vstupem funkce eval()“ je v spojení s Javascriptom úplná hlúposť. Javascript beží u klienta, teda mi umožňuje spustiť akýkoľvek kód alebo bežiaci kód akokoľvek modifikovať. Bez ohľadu na to, či tam eval mám, alebo nie.
To se asi týká případu, kdy hodnota přijde jako GET parametr (tedy potenciálně od útočníka, který poslal oběti odkaz), projde skrz server, kde se dostane do řetězce určeného pro eval() a na straně klienta se vykoná jako JavaScript a má stejná práva jako kód z dané domény (přestože pochází z jiné, od útočníka).
Ak je programátor taký idiot, že Javascriptový kód pchá do query stringu, je to rovnako deravé, či sa použije, alebo nepoužije eval.