Comparing version 0.1.0-pre.2 to 0.2.0
@@ -1,3 +0,3 @@ | ||
/*jshint strict:false */ | ||
module.exports = function( grunt ) { | ||
module.exports = function (grunt) { | ||
'use strict'; | ||
@@ -8,5 +8,5 @@ grunt.initConfig({ | ||
options: { | ||
jshintrc : ".jshintrc" | ||
jshintrc : '.jshintrc' | ||
}, | ||
all: [ "lib/**/*.js", "test/**/*.js" ] | ||
all: [ 'lib/**/*.js', 'test/**/*.js', 'gruntfile.js' ] | ||
}, | ||
@@ -16,6 +16,6 @@ | ||
options: { | ||
ui: "bdd", | ||
reporter: "spec" | ||
ui: 'bdd', | ||
reporter: 'spec' | ||
}, | ||
all: "test/specs/**/*.js" | ||
all: 'test/**/*.js' | ||
} | ||
@@ -25,8 +25,8 @@ | ||
grunt.loadNpmTasks("grunt-contrib-jshint"); | ||
grunt.loadNpmTasks("grunt-simple-mocha"); | ||
grunt.loadNpmTasks('grunt-contrib-jshint'); | ||
grunt.loadNpmTasks('grunt-simple-mocha'); | ||
grunt.loadNpmTasks('grunt-release'); | ||
grunt.registerTask("default", [ "jshint", "simplemocha" ]); | ||
grunt.registerTask('default', [ 'jshint', 'simplemocha' ]); | ||
}; |
110
lib/tree.js
@@ -1,69 +0,81 @@ | ||
var falafel = require("falafel"); | ||
var helpers = require("./helpers"); | ||
var types = require("./types"); | ||
var esprima = require('esprima'); | ||
var escodegen = require('escodegen'); | ||
var traverse = require('traverse'); | ||
var utils = require('./util/utils'); | ||
var Variable = require('./nodes/variable'); | ||
var CallExpression = require('./nodes/CallExpression'); | ||
var AssignmentExpression = require('./nodes/AssignmentExpression'); | ||
var Body = require('./nodes/Body'); | ||
module.exports = Tree; | ||
function Tree(source) { | ||
this.tree = esprima.parse(source); | ||
this.body = new Body(this.tree.body); | ||
} | ||
/** | ||
* Queriable AST Tree constructor | ||
* @param {String} src Source code string | ||
* Return the regenerated code string | ||
* @return {String} outputted code | ||
*/ | ||
function Tree( src ) { | ||
this.src = src; | ||
this.tokens = []; | ||
} | ||
Tree.prototype.toString = function () { | ||
// Filter the three to remove temporary placeholders | ||
var tree = traverse(this.tree).map(function (node) { | ||
if (node && node.TEMP === true) { | ||
this.remove(); | ||
} | ||
}); | ||
return escodegen.generate(tree); | ||
}; | ||
/** | ||
* Get the compiled source string | ||
* @return {String} source code | ||
* Find variables declaration | ||
* @param {String} name Name of the declared variable | ||
* @return {Variable} | ||
*/ | ||
Tree.prototype.toString = function() { | ||
return this._process().src; | ||
Tree.prototype.var = function (name) { | ||
var nodes = traverse(this.tree).nodes().filter(function (node) { | ||
if (node && node.type === 'VariableDeclarator' && node.id.name === name) { | ||
return true; | ||
} | ||
}); | ||
return new Variable(nodes); | ||
}; | ||
/** | ||
* Compile the source by passing control to registered tokens | ||
* @return {Self} Tree | ||
* Select function/method calls | ||
* @param {String} name Name of the called function (`foo`, `foo.bar`) | ||
* @return {CallExpression} | ||
*/ | ||
Tree.prototype._process = function() { | ||
var self = this; | ||
var output = falafel( this.src, helpers.unbox(this.tokens, "use")); | ||
this.src = output.toString(); | ||
this.tokens.length = 0; | ||
return this; | ||
}; | ||
Tree.prototype.callExpression = function (name) { | ||
var nodes = traverse(this.tree).nodes().filter(function (node) { | ||
if (!node || node.type !== 'CallExpression') return false; | ||
// Simple function call | ||
if (node.callee.type === 'Identifier' && node.callee.name === name) return true; | ||
// --- | ||
// Token types | ||
// Method call | ||
if (utils.matchMemberExpression(name, node.callee)) return true; | ||
}); | ||
return new CallExpression(nodes); | ||
}; | ||
/** | ||
* Add a variable token to the queue | ||
* @param {string} name Variable name | ||
* @return {Var token} Selected variable token | ||
* Select an AssignmentExpression node | ||
* @param {String} assignedTo Name of assignement left handside | ||
* @return {AssignmentExpression} Matched node | ||
*/ | ||
Tree.prototype.var = function( name ) { | ||
var token = new types.Var(name); | ||
this.tokens.push( token ); | ||
return token; | ||
}; | ||
Tree.prototype.assignment = function (assignedTo) { | ||
var nodes = traverse(this.tree).nodes().filter(function (node) { | ||
if (!node || node.type !== 'AssignmentExpression') return false; | ||
/** | ||
* Add an object token to the queue | ||
* @return {Var token} Selected variable token | ||
*/ | ||
Tree.prototype.object = function() { | ||
var token = new types.Object(); | ||
this.tokens.push( token ); | ||
return token; | ||
// Simple assignement | ||
if (node.left.type === 'Identifier' && node.left.name === assignedTo) return true; | ||
// Assignement to an object key | ||
if (utils.matchMemberExpression(assignedTo, node.left)) return true; | ||
}); | ||
return new AssignmentExpression(nodes); | ||
}; | ||
/** | ||
* Add an array token to the queue | ||
* @return {Var token} Selected variable token | ||
*/ | ||
Tree.prototype.array = function() { | ||
var token = new types.Array(); | ||
this.tokens.push( token ); | ||
return token; | ||
module.exports = function (source) { | ||
return new Tree(source); | ||
}; |
{ | ||
"name": "ast-query", | ||
"version": "0.1.0-pre.2", | ||
"version": "0.2.0", | ||
"description": "Declarative JavaScript AST modification façade", | ||
@@ -8,3 +8,9 @@ "main": "lib/tree.js", | ||
"license": "MIT", | ||
"keywords": [ "AST", "source", "traversal", "syntax", "tree" ], | ||
"keywords": [ | ||
"AST", | ||
"source", | ||
"traversal", | ||
"syntax", | ||
"tree" | ||
], | ||
"scripts": { | ||
@@ -18,6 +24,9 @@ "test": "grunt" | ||
"dependencies": { | ||
"falafel": "~0.3.1" | ||
"esprima": "~1.0.4", | ||
"escodegen": "~1.2.0", | ||
"lodash": "~2.4.1", | ||
"traverse": "~0.6.6", | ||
"class-extend": "~0.1.1" | ||
}, | ||
"devDependencies": { | ||
"chai": "~1.7.2", | ||
"grunt": "~0.4.1", | ||
@@ -24,0 +33,0 @@ "grunt-cli": "~0.1.9", |
205
README.md
AST Query | ||
================ | ||
Tentative to a simple JavaScript AST modification library. | ||
This project is a tentative to create a simple JavaScript AST modification library. | ||
If you've ever worked with AST trying to edit source code, you've probably had a hard time | ||
as the syntax is somehow terse and you need to loop and use conditionnals a lot. AST Query | ||
try to hide this complexity behind a declarative façade. | ||
If you've ever worked with AST trying to edit source code, you'll know it is a bad time. AST syntax is terse and forces you to loop a three and use conditionals structure a lot. AST Query hide this complexity behind a declarative façade. | ||
Making this choice, AST Query does not try to cover a full AST API, but instead answer | ||
common needs. | ||
Making the simplicity choice means AST Query won't try to cover the full AST API. Rather we strive to answer commons needs. | ||
@@ -19,12 +16,13 @@ | ||
First, you always need to create a `Tree` which you'll edit | ||
First, you need to pass a program code into AST query: | ||
``` javascript | ||
var Tree = require("ast-query"); | ||
var tree = new Tree("var a = 'foo'"); | ||
var program = require("ast-query"); | ||
var tree = program("var a = 'foo'"); | ||
``` | ||
To get the source code back after modifying the AST, call the `toString` method on the | ||
tree. | ||
This function returns a wrapped AST tree you can query and modify. | ||
Once you've modified the AST, get the source code back by calling the `toString` method on the tree. | ||
``` javascript | ||
@@ -38,120 +36,143 @@ // ... | ||
Reminder you're editing source code. As so, you'll need to add extra quotes when outputting | ||
strings (e.g.: `"'foo'"`). | ||
Remember that you are editing source code. This mean you provide raw source code strings. This mean you need to double wrap strings (e.g.: `"'foo'"`). If that's not done, AST-query assume you're referencing a variable called `foo`. | ||
Also, note that AST Query isn't checking you output valid code; neither does it check for | ||
whitespace consistency. You may want to pass each transformed sources in a beautifier if | ||
this is important. | ||
API | ||
================ | ||
Tree | ||
Program | ||
---------------- | ||
### `new Tree( sourceCode )` | ||
- **sourceCode** | ||
- type: String | ||
- The source code to edit. | ||
### `var tree = program( sourceCode )` | ||
- **sourceCode** (String) - The source code to edit. | ||
Returns an AST tree you can then query as explained below: | ||
### `tree.var( name )` | ||
- **name** | ||
- type: String | ||
- The variable name | ||
- Returns: A `variable` token. [See object methods](#variable-token) | ||
- **name** (String) - The variable name | ||
### `tree.object()` | ||
- Returns: An `object` literal token. [See object methods](#object-literal-token) | ||
Find and returns a [`Variable` node](#variable-node). | ||
Given this code | ||
Variable token | ||
``` js | ||
var bar = 23; | ||
``` | ||
You'd call `tree.var('bar')` to get the Variable node. | ||
### `tree.callExpression( name )` | ||
- **name** (String) - The name of the function or method being called. | ||
Find a function or method call and return a [`CallExpression` node](#callexpression-node) | ||
Given this code | ||
```js | ||
grunt.initConfig({}); | ||
``` | ||
You'd call `tree.callExpression('grunt.initConfig')` to get the CallExpression node. | ||
### `tree.assignment( assignedTo )` | ||
- **assignedTo** (String) - The name (name or object) a value is assigned to | ||
Find and return an [`AssignementExpression` node](#AssignementExpression-node). | ||
You'd call `tree.assignment('module.exports')` to query the code below: | ||
```js | ||
module.exports = function () { | ||
// code | ||
}; | ||
``` | ||
### `tree.body` | ||
Property representing the program body in a [`Body` node](#body-node). | ||
Variable node | ||
----------------- | ||
### `.value( value )` | ||
- **value** | ||
- type: String|function | ||
- A string containing the new variable value or a function taking the current value as | ||
a parameter and returning the new variable value | ||
- **value** (String) _optionnal_ - A string containing the new variable value. | ||
It returns the current or new value wrapped in AST query interface. | ||
### `.rename( name )` | ||
- **name** | ||
- type: String | ||
- Change the variable name | ||
- **name** (String) - Change the variable name | ||
### `.replaceWith( value )` | ||
- **value** | ||
- type: String | ||
- Replace the current variable declaration string with a new one. Note this method only | ||
replace the string between the var declarations tokens, e.g. `var <value goes here>;` | ||
CallExpression node | ||
-------------------- | ||
### `.insertAfter( value )` | ||
- **value** | ||
- type: String | ||
- Insert a string after the variable declaration code blocks. If there's multiple | ||
declaration inside the code block, the string will be inserted after everyone. | ||
### `.filter( iterator )` | ||
- **iterator** (Function) - Function receiving each node as arguments and returning true to keep the current node in the returned set. | ||
### `.insertBefore( value )` | ||
- **value** | ||
- type: String | ||
- Insert a string before the `var` keyword | ||
Return a new CallExpression nodes collection with nodes passing the iterator test. | ||
### `.delete()` | ||
- Delete the variable declaration. If the declaration block contain a single variable, | ||
it'll delete it all, otherwise, it'll only delete the relevant section | ||
### `.arguments` | ||
A property pointing to an [`ArrayExpression` node] referencing the called function arguments. | ||
Object literal token | ||
AssignementExpression node | ||
-------------------- | ||
### `.assignedTo( name )` | ||
- **name** | ||
- type: String | ||
- Only select object assigned to a `var`. | ||
### `.value( value )` | ||
### `.passedTo( name )` | ||
- **name** | ||
- type: String | ||
- Only select object passed as argument to a `function` or a `method` | ||
- Known issue: Currently only work with objects nested two levels down. (PR welcomed) | ||
Replace the assignement value with a new value or return the current value wrapped in an AST query interface. | ||
Example: | ||
```javascript | ||
var tree = new Tree("grunt.init({ key: 'value' })"); | ||
tree.object().passedTo("grunt.init").key("key").value("'foo'"); | ||
console.log( tree.toString() ); | ||
``` | ||
Literal node | ||
-------------------- | ||
### `.key( name )` | ||
- **name** | ||
- type: String | ||
- A key name to select | ||
- Returns: A `Property` token. [See object methods](#property-token) | ||
A Literal node represent a raw JavaScript value as a String, a Number or a Boolean. | ||
### `.value( value )` | ||
Property token | ||
------------------ | ||
Get or update the value. | ||
### `.value( value )` | ||
- **value** | ||
- type: String|function | ||
- A string containing the new property value or a function taking the current value as | ||
a parameter and returning the new property value | ||
FunctionExpression node | ||
------------------- | ||
### `.rename( name )` | ||
- **name** | ||
- type: String | ||
- Change the variable property key | ||
Node representing a function declaration (e.g. `function () {}`). | ||
### `.delete()` | ||
- Delete the property from the object. | ||
### `.body` | ||
Property pointing to a [`Body` node](#body-node) representing the function expression body. | ||
ObjectExpression node | ||
------------------- | ||
### `.key( name )` | ||
- **name** | ||
- type: String | ||
- If the property value is an object, key name to select (if value is not an object, this | ||
condition is just ignored). | ||
- Returns: A `Property` token. | ||
- **name** (String) - Key name | ||
Get a key value object or create a blank placeholder | ||
### `value( value )` | ||
Replace current node with a new value. Returns the new value wrapped. | ||
ArrayExpression node | ||
------------------- | ||
### `.push( value )` | ||
- **value** (String) - value to push in the array | ||
### `.unshift( value )` | ||
- **value** (String) - value to unshift in the array | ||
### `.at( index )` | ||
- **index** (Number) - Index of the value to fetch | ||
Returns a value wrapped in an AST query interface. | ||
Body node | ||
------------------- | ||
### `.prepend( code )` | ||
Preprend the given code lines in the body. If a `"use strict";` statement is present, it always stay first. | ||
### `.append( code )` | ||
Append the given code lines in the body. | ||
Contributing | ||
@@ -158,0 +179,0 @@ ===================== |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
5
28
194
29856
5
662
1
+ Addedclass-extend@~0.1.1
+ Addedescodegen@~1.2.0
+ Addedesprima@~1.0.4
+ Addedlodash@~2.4.1
+ Addedtraverse@~0.6.6
+ Addedamdefine@1.0.1(transitive)
+ Addedarray-buffer-byte-length@1.0.2(transitive)
+ Addedarraybuffer.prototype.slice@1.0.4(transitive)
+ Addedavailable-typed-arrays@1.0.7(transitive)
+ Addedcall-bind@1.0.8(transitive)
+ Addedcall-bind-apply-helpers@1.0.1(transitive)
+ Addedcall-bound@1.0.3(transitive)
+ Addedclass-extend@0.1.2(transitive)
+ Addeddata-view-buffer@1.0.2(transitive)
+ Addeddata-view-byte-length@1.0.2(transitive)
+ Addeddata-view-byte-offset@1.0.1(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addeddefine-properties@1.2.1(transitive)
+ Addeddunder-proto@1.0.1(transitive)
+ Addedes-abstract@1.23.9(transitive)
+ Addedes-define-property@1.0.1(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedes-object-atoms@1.1.1(transitive)
+ Addedes-set-tostringtag@2.1.0(transitive)
+ Addedes-to-primitive@1.3.0(transitive)
+ Addedescodegen@1.2.0(transitive)
+ Addedesprima@1.0.4(transitive)
+ Addedestraverse@1.5.1(transitive)
+ Addedesutils@1.0.0(transitive)
+ Addedfor-each@0.3.3(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedfunction.prototype.name@1.1.8(transitive)
+ Addedfunctions-have-names@1.2.3(transitive)
+ Addedget-intrinsic@1.2.7(transitive)
+ Addedget-proto@1.0.1(transitive)
+ Addedget-symbol-description@1.1.0(transitive)
+ Addedglobalthis@1.0.4(transitive)
+ Addedgopd@1.2.0(transitive)
+ Addedhas-bigints@1.1.0(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-proto@1.2.0(transitive)
+ Addedhas-symbols@1.1.0(transitive)
+ Addedhas-tostringtag@1.0.2(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedinternal-slot@1.1.0(transitive)
+ Addedis-array-buffer@3.0.5(transitive)
+ Addedis-async-function@2.1.0(transitive)
+ Addedis-bigint@1.1.0(transitive)
+ Addedis-boolean-object@1.2.1(transitive)
+ Addedis-callable@1.2.7(transitive)
+ Addedis-data-view@1.0.2(transitive)
+ Addedis-date-object@1.1.0(transitive)
+ Addedis-finalizationregistry@1.1.1(transitive)
+ Addedis-generator-function@1.1.0(transitive)
+ Addedis-map@2.0.3(transitive)
+ Addedis-number-object@1.1.1(transitive)
+ Addedis-regex@1.2.1(transitive)
+ Addedis-set@2.0.3(transitive)
+ Addedis-shared-array-buffer@1.0.4(transitive)
+ Addedis-string@1.1.1(transitive)
+ Addedis-symbol@1.1.1(transitive)
+ Addedis-typed-array@1.1.15(transitive)
+ Addedis-weakmap@2.0.2(transitive)
+ Addedis-weakref@1.1.0(transitive)
+ Addedis-weakset@2.0.4(transitive)
+ Addedisarray@2.0.5(transitive)
+ Addedlodash@2.4.2(transitive)
+ Addedmath-intrinsics@1.1.0(transitive)
+ Addedobject-assign@2.1.1(transitive)
+ Addedobject-inspect@1.13.3(transitive)
+ Addedobject-keys@1.1.1(transitive)
+ Addedobject.assign@4.1.7(transitive)
+ Addedown-keys@1.0.1(transitive)
+ Addedpossible-typed-array-names@1.0.0(transitive)
+ Addedreflect.getprototypeof@1.0.10(transitive)
+ Addedregexp.prototype.flags@1.5.4(transitive)
+ Addedsafe-array-concat@1.1.3(transitive)
+ Addedsafe-push-apply@1.0.0(transitive)
+ Addedsafe-regex-test@1.1.0(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedset-function-name@2.0.2(transitive)
+ Addedset-proto@1.0.0(transitive)
+ Addedside-channel@1.1.0(transitive)
+ Addedside-channel-list@1.0.0(transitive)
+ Addedside-channel-map@1.0.1(transitive)
+ Addedside-channel-weakmap@1.0.2(transitive)
+ Addedsource-map@0.1.43(transitive)
+ Addedstring.prototype.trim@1.2.10(transitive)
+ Addedstring.prototype.trimend@1.0.9(transitive)
+ Addedstring.prototype.trimstart@1.0.8(transitive)
+ Addedtraverse@0.6.11(transitive)
+ Addedtyped-array-buffer@1.0.3(transitive)
+ Addedtyped-array-byte-length@1.0.3(transitive)
+ Addedtyped-array-byte-offset@1.0.4(transitive)
+ Addedtyped-array-length@1.0.7(transitive)
+ Addedtypedarray.prototype.slice@1.0.5(transitive)
+ Addedunbox-primitive@1.1.0(transitive)
+ Addedwhich-boxed-primitive@1.1.1(transitive)
+ Addedwhich-builtin-type@1.2.1(transitive)
+ Addedwhich-collection@1.0.2(transitive)
+ Addedwhich-typed-array@1.1.18(transitive)
- Removedfalafel@~0.3.1
- Removedfalafel@0.3.1(transitive)