Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Reimported code (by @omarkhan and @frostedcheerios) for requirejs on …

…top of master, #4 .
  • Loading branch information...
commit 028759f6db5322f9c1e66ede804aea9c5113e0ce 1 parent c3a4e83
@ddlsmurf ddlsmurf authored
View
1  src/coffeedoc.coffee
@@ -24,6 +24,7 @@ exports.documentModule = (script, parser) ->
AST parsers are defined in the `parsers.coffee` module
###
nodes = getNodes(script)
+ nodes = parser.getNodes(nodes) if parser.getNodes
first_obj = nodes[0]
if first_obj?.type == 'Comment'
docstring = formatDocstring(first_obj.comment)
View
8 src/docgen.coffee
@@ -18,7 +18,7 @@ parsers = require(__dirname + '/parsers')
OPTIONS =
'-o, --output': 'Set output directory (default: ./docs)'
'--commonjs ': 'Use if target scripts use CommonJS for module loading (default)'
-# '--requirejs ': 'Use if target scripts use RequireJS for module loading'
+ '--requirejs ': 'Use if target scripts use RequireJS for module loading'
help = ->
### Show help message and exit ###
@@ -42,9 +42,9 @@ if '-h' in opts or '--help' in opts
if '--commonjs' in opts
opts.shift()
parser = new parsers.CommonJSParser()
-#else if '--requirejs' in opts
-# opts.shift()
-# parser = new parsers.RequireJSParser()
+else if '--requirejs' in opts
+ opts.shift()
+ parser = new parsers.RequireJSParser()
else
parser = new parsers.CommonJSParser()
if opts.length == 0
View
24 src/helpers.coffee
@@ -16,7 +16,7 @@ exports.getNodes = (script) ->
root_node = coffeescript.nodes(script)
root_node.traverseChildren false, (node) ->
node.type = node.constructor.name
- return root_node.expressions
+ return [root_node].concat(root_node.expressions)
exports.getFullName = (variable) ->
###
@@ -27,3 +27,25 @@ exports.getFullName = (variable) ->
name += '.' + (p.name.value for p in variable.properties).join('.')
return name
+exports.getAttr = (node, path) ->
+ ###
+ Safe function for looking up paths in the AST. If an attribute is
+ undefined at any part of the path, an object with is returned with the
+ type attribute set to null
+ ###
+ path = path.split('.')
+ nullObj = {type: null}
+ for attr in path
+ index = null
+ if '[' in attr
+ [attr, index] = attr.split('[')
+ index = index[..-2]
+
+ node = node[attr]
+ if not node?
+ return nullObj
+ if index?
+ node = node[parseInt(index)]
+ if not node?
+ return nullObj
+ return node
View
157 src/parsers.coffee
@@ -85,6 +85,157 @@ exports.CommonJSParser = class CommonJSParser extends BaseParser
exports.RequireJSParser = class RequireJSParser extends BaseParser
- ###
- Not yet implemented
- ###
+ ###
+ Not yet tested
+ ###
+ getNodes: (nodes, debug=false) ->
+ result_nodes = []
+ moduleLdrs = ['define', 'require']
+ for root_node in nodes
+ root_node.traverseChildren false, (node) ->
+ node.type = node.constructor.name
+ node.level = 1
+ if node.type is 'Call' and node.variable.base.value in moduleLdrs
+ for arg in node.args
+ if arg.constructor.name is 'Code'
+ arg.body.traverseChildren false, (node) ->
+ node.type = node.constructor.name
+ node.level = 2
+ if debug
+ console.log(node)
+ result_nodes = result_nodes.concat(arg.body.expressions)
+ # TODO: Support objects passed to require or define
+ if debug
+ console.log(node)
+ return nodes.concat(result_nodes)
+
+ _parseCall: (node, deps) ->
+ ### Parse require([], ->) and define([], ->) ###
+ mods = []
+ args = []
+
+ for arg in node.args
+ val1 = getAttr(arg, 'base')
+ val2 = getAttr(arg, 'base.body.expressions[0]')
+ if val1.type is 'Arr'
+ mods = @_parseModuleArray(val1)
+ else if val2.type is 'Code'
+ args = @_parseFuncArgs(val2)
+ else if arg.type is 'Code'
+ args = @_parseFuncArgs(arg)
+
+ @_matchArgs(deps, mods, args)
+
+ _parseAssign: (node, deps) ->
+ ### Parse module = require("path/to/module") ###
+ arg = node.value.args[0]
+ module_path = @_getModulePath(arg)
+ if module_path?
+ local_name = helpers.getFullName(node.variable)
+ deps[local_name] = module_path
+
+ _parseObject: (node, deps) ->
+ ### Parse require = {} ###
+ obj = node.value.base
+ mods = []
+ args = []
+ for attr in obj.properties
+ name = helpers.getAttr(attr, 'variable.base.value')
+ val1 = helpers.getAttr(attr, 'value.base')
+ val2 = helpers.getAttr(attr, 'value.base.body.expressions[0]')
+ if name is 'deps' and val1.type is 'Arr'
+ mods = @_parseModuleArray(val1)
+ else if name is 'callback'
+ if val2.type is 'Code'
+ args = @_parseFuncArgs(val2)
+ else if attr.value.type is 'Code'
+ args = @_parseFuncArgs(attr.value)
+
+ @_matchArgs(deps, mods, args)
+
+ _matchArgs: (deps, mods, args) ->
+ ###
+ Match the list of modules to the list of local variable names and
+ add them to the dependencies object given.
+ ###
+ index = 0
+ for mod in mods
+ local_name = if index < args.length then args[index] else mod
+ deps[local_name] = mod
+ index++
+
+ _stripQuotes: (str) ->
+ return str.replace(/('|\")/g, '')
+
+ _parseFuncArgs: (func) ->
+ ###
+ Given a node of type 'Code', gathers the names of each of the function
+ arguments and return them in an array.
+ ###
+ args = []
+ for arg in func.params
+ args.push(arg.name.value)
+ return args
+
+ _parseModuleArray: (arr) ->
+ ###
+ Given a node of type 'Arr', gathers the module paths represented by
+ each object in the array and returns them in an array.
+ ###
+ modules = []
+ for module in arr.objects
+ mod_path = @_getModulePath(module)
+ if mod_path?
+ modules.push(mod_path)
+ return modules
+
+ _getModulePath: (mod) ->
+ if mod.type is 'Value'
+ return @_stripQuotes(mod.base.value)
+ else if mod.type is 'Op' and mod.operator is '+'
+ return '.' + @_stripQuotes(mod.second.base.value)
+ return null
+
+ getDependencies: (nodes) ->
+ ###
+ This currently works with the following `require` calls:
+
+ local_name = require("path/to/module")
+ local_name = require(__dirname + "/path/to/module")
+
+ The following `require` object assignments:
+
+ require = {deps: ["path/to/module"]}
+ require = {deps: ["path/to/module"], callback: (module) ->}
+
+ And the following `require and `define` calls:
+
+ require(["path/to/module"], (module) -> ...)
+ require({}, ["path/to/module"], (module) -> ...)
+ define(["path/to/module"], (module) -> ...)
+ define('', ["path/to/module"], (module) -> ...)
+
+ ###
+ deps = {}
+ for n in nodes
+ if n.type is 'Call' and n.variable.base.value in ['define', 'require']
+ @_parseCall(n, deps)
+ else if n.type is 'Assign'
+ if n.value.type is 'Call' and n.value.variable.base.value is 'require'
+ @_parseAssign(n, deps)
+ else if (n.level is 1 and n.variable.base.value is 'require' \
+ and n.value.base.type is 'Obj')
+ @_parseObject(n, deps)
+ return deps
+
+ getClasses: (nodes) ->
+ return (n for n in nodes when n.type == 'Class' \
+ or n.type == 'Assign' and n.value.type == 'Class')
+
+ getObjects: (nodes) ->
+ return (n for n in nodes when n.type == 'Assign' \
+ and helpers.getAttr(n, 'value.base').type == 'Obj')
+
+ getFunctions: (nodes) ->
+ return (n for n in nodes \
+ when n.type == 'Assign' and n.value.type == 'Code')
Please sign in to comment.
Something went wrong with that request. Please try again.