strong-trace
Version:
StrongTrace Node.js Tracer
74 lines (57 loc) • 2.36 kB
Markdown
scopenodes
=====
Find the AST nodes from a string of JavaScript that define scope. E.g. The outer Program scope and functions.
Example
```javascript
var scopenodes = require("./scopenodes")
var fs = require("fs")
var filename = process.argv[2] || "./test/lib/nested.js"
var content = fs.readFileSync(filename).toString()
var out = scopenodes(content)
console.log(out)
/*
[ { type: 'Program',
body: [ [Object], [Object] ],
range: [ 0, 116 ],
loc: { start: [Object], end: [Object] },
path: [],
parent: null },
{ type: 'BlockStatement',
body: [ [Object] ],
range: [ 21, 69 ],
loc: { start: [Object], end: [Object] },
path: [ [Object] ],
parent:
{ type: 'FunctionDeclaration',
id: [Object],
params: [Object],
...
*/
```
API
===
`scopenodes(jsString)`
Will return a list of nodes from an AST (Esprima) that define scoped blocks of the provided JavaScript string.
It will add some properties to each node:
* fnName: An attempted guess at the function name. It should always be right if the function is named.
* path: A list of outer scopes in order of scopechain for this node
* parent: For a FunctionDeclaration or FunctionExpression node, the declaration or expression.
* isStrict: a boolean value as to whether *THIS SCOPE SPECIFICALLY* has declared strict mode. Does not account for inherited strict mode.
Naming generally works like the following, and may change as we go:
1. If the function is named, use that name.
2. If it is an assigment, use what it is assigned to
3. If it is a function call argument or `new` argument, call it "fnName() fn argument" where fnName is the function called.
4. If the call is complex (contains a parenthesis) attempt to remove all but the last bit. (e.g. foo.map(...).sort(...).forEach(...) will become ".forEach() fn argument")
5. If the function looks like listener for an on event (e.g. `foo.on('exit', ...))` call it `foo.on 'exit' listener`
6. In any of the above cases if that name has already been assigned, start indexing the names like so: foo, foo{2}, foo{3}, etc.
Naming nests with scope, so if you have code such as this:
```js
function foo() {
function bar() {
// ...
}
}
```
The two functions would be named `foo` and `foo>bar` denoting that this bar is the one defind in the scope of `foo`.