Static scope analysis and transpilation of ES6 block scoped const
and let
variables, to ES3.
Node already supports const
and let
so you can use that today
(run node --harmony
and "use strict"
). defs.js
enables you to do the same
for browser code. While developing you can rely on the experimental support
in Chrome (chrome://flags, check Enable experimental JavaScript). defs.js
is
also a pretty decent static scope analyzer/linter.
The talk
LET's CONST together, right now (with ES3)
from Front-Trends 2013
(slides) includes
more information about let
, const
and defs.js
. See also the blog post
ES3 <3 block scoped const and let => defs.js.
npm install -g defs
Then run it as defs file.js
. The errors (if any) will go to stderr,
the transpiled source to stdout
, so redirect it like defs file.js > output.js
.
More command line options are coming.
There's also a Grunt plugin, see grunt-defs.
See BUILD.md for a description of the self-build and the browser bundle.
MIT
, see LICENSE file.
See CHANGES.md.
defs
looks for a defs-config.json
configuration file in your current
directory. If not found there, it searches parent directories until it hits /
.
Example defs-config.json
:
{
"environments": ["node", "browser"],
"globals": {
"my": false,
"hat": true
},
"loopClosures": "iife",
"disallowVars": false,
"disallowDuplicated": true,
"disallowUnknownReferences": true
}
globals
lets you list your program's globals, and indicate whether they are
writable (true
) or read-only (false
), just like jshint
.
environments
lets you import a set of pre-defined globals, here node
and
browser
. These default environments are borrowed from jshint
(see
jshint_globals/vars.js).
loopClosures
(defaults to false
) can be set to "iife" to enable transformation
of loop-closures via immediately-invoked function expressions.
disallowVars
(defaults to false
) can be enabled to make
usage of var
an error.
disallowDuplicated
(defaults to true
) errors on duplicated
var
definitions in the same function scope.
disallowUnknownReferences
(defaults to true
) errors on references to
unknown global variables.
ast
(defaults to false
) produces an AST instead of source code
(experimental).
stats
(defaults to false
) prints const/let statistics and renames
(experimental).
parse
(defaults to null
) lets you provide a custom parse function if you
use defs as an API. By default it will use require("esprima").parse
.
Input example.js
:
"use strict";
function fn() {
const y = 0;
for (let x = 0; x < 10; x++) {
const y = x * 2;
const z = y;
}
console.log(y); // prints 0
}
fn();
Output from running defs example.js
:
"use strict";
function fn() {
var y = 0;
for (var x = 0; x < 10; x++) {
var y$0 = x * 2;
var z = y$0;
}
console.log(y); // prints 0
}
fn();
npm install defs
, then:
const defs = require("defs");
const options = {};
const src = "const x = 1";
const res = defs(src, options);
assert(res.src === "var x = 1");
// you can also pass an AST (with loc and range) instead of a string to defs
const ast = require("esprima").parse(src, {loc: true, range: true});
const res = defs(ast, {ast: true}); // AST-in, AST-out
// inspect res.ast
res object:
{
src: string // on success
errors: array of error messages // on errors
stats: statistics object (toStringable)
ast: transformed ast // when options.ast is set
}
defs.js
strives to transpile your program as true to ES6 block scope semantics as
possible while being as maximally non-intrusive as possible.
It can optionally transform loop closures via IIFE's (when possible), if you include
"loopClosures": "iife"
in your defs-config.json
. More info in
loop-closures.md.
See semantic-differences.md for other minor differences.