Class: ParseJS::ExtractDocs

Inherits:
CommentScanner show all
Includes:
AST
Defined in:
lib/parsejs/docs.rb

Instance Method Summary collapse

Methods inherited from CommentScanner

#comment?, #print_comment, #stringify, #strip_leading_whitespace, #visit_CommentedStatement

Methods inherited from Visitor

#accept, #map, #visit, #visit_ArrayExpression, #visit_BinaryExpression, #visit_BlockStatement, #visit_BreakStatement, #visit_CallExpression, #visit_CatchClause, #visit_Comment, #visit_CommentedStatement, #visit_ConditionalExpression, #visit_ContinueStatement, #visit_DebuggerStatement, #visit_DoWhileStatement, #visit_EmptyStatement, #visit_ExpressionStatement, #visit_ForInStatement, #visit_ForStatement, #visit_Identifier, #visit_IfStatement, #visit_Literal, #visit_LogicalExpression, #visit_MemberExpression, #visit_NewExpression, #visit_Number, #visit_ObjectExpression, #visit_ParameterList, #visit_RegExp, #visit_ReturnStatement, #visit_SequenceExpression, #visit_String, #visit_SwitchCase, #visit_SwitchStatement, #visit_ThisExpression, #visit_ThrowStatement, #visit_TryStatement, #visit_UnaryExpression, #visit_UpdateExpression, #visit_VariableDeclaration, #visit_VariableDeclarator, #visit_WhileStatement, #visit_WithStatement

Constructor Details

#initializeExtractDocs

Returns a new instance of ExtractDocs.



70
71
72
73
# File 'lib/parsejs/docs.rb', line 70

def initialize(*)
  @current_variables = []
  @current_class = []
end

Instance Method Details

#build_namespace(namespace) ⇒ Object



157
158
159
160
161
162
163
164
165
166
# File 'lib/parsejs/docs.rb', line 157

def build_namespace(namespace)
  if namespace.empty?
    YARD::Registry.root
  elsif ns = YARD::Registry.at(namespace)
    ns
  else
    name = namespace.gsub('::', '.')
    YARD::CodeObjects::NamespaceObject.new(:root, name)
  end
end

#current_class_nameObject



168
169
170
171
# File 'lib/parsejs/docs.rb', line 168

def current_class_name
  klass, parent = @current_class.last
  "#{klass} < #{parent}"
end

#current_yard_classObject



173
174
175
# File 'lib/parsejs/docs.rb', line 173

def current_yard_class
  @current_class.last[2]
end

#member_left(expr) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/parsejs/docs.rb', line 101

def member_left(expr)
  object = expr

  while object
    if object.is_a?(Identifier)
      return object.val
    elsif object.is_a?(ThisExpression)
      return "this"
    elsif object.respond_to?(:object)
      object = object.object
    else
      return nil
    end
  end
end

#process_commentObject



205
206
# File 'lib/parsejs/docs.rb', line 205

def process_comment(*)
end

#stripped_commentObject



194
195
196
197
198
199
200
201
202
203
# File 'lib/parsejs/docs.rb', line 194

def stripped_comment
  comments = @current_comment.map do |c|
    next unless c.multiline?
    c.body
  end

  string = comments.join("\n")
  string = string.gsub(/\A\**\n/, '')
  strip_leading_whitespace(string)
end

#variable?(name) ⇒ Boolean

Returns:

  • (Boolean)


95
96
97
98
99
# File 'lib/parsejs/docs.rb', line 95

def variable?(name)
  @current_variables.find do |list|
    list.include?(name)
  end
end

#visit_AssignmentExpression(expr) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/parsejs/docs.rb', line 117

def visit_AssignmentExpression(expr)
  right = expr.right
  in_class = false

  if right.is_a?(CallExpression)
    callee = expr.right.callee
    if callee.is_a?(MemberExpression) && !callee.computed
      property = callee.property.val
      if property == "extend"
        if expr.left.is_a?(MemberExpression)
          left_id = member_left(expr.left)
          extends = stringify(expr.right.callee).sub(/\.extend$/, '')

          if variable?(left_id)
            # found private class
          else
            klass = stringify(expr.left)

            left_string = stringify(expr.left)
            namespace_obj = build_namespace left_string.split(".")[0...-1].join("::")

            class_name = left_string.split(".")[-1]

            obj = YARD::CodeObjects::ClassObject.new(namespace_obj, class_name)
            obj.docstring = stripped_comment

            @current_class.push [klass, extends, obj]
            in_class = true
          end
        end
      end
    end
  end

  super

ensure
  @current_class.pop if in_class
end

#visit_FunctionDeclaration(decl) ⇒ Object



79
80
81
# File 'lib/parsejs/docs.rb', line 79

def visit_FunctionDeclaration(decl)
  with_variables(decl, decl.params.list.map(&:val)) { super }
end

#visit_FunctionExpression(expr) ⇒ Object



83
84
85
# File 'lib/parsejs/docs.rb', line 83

def visit_FunctionExpression(expr)
  with_variables(expr, expr.params.list.map(&:val)) { super }
end

#visit_Program(program) ⇒ Object



75
76
77
# File 'lib/parsejs/docs.rb', line 75

def visit_Program(program)
  with_variables(program, []) { super }
end

#visit_Property(property) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/parsejs/docs.rb', line 177

def visit_Property(property)
  return if @current_class.empty?

  @current_comment = property.comments
  return if stripped_comment.empty?

  case property.value
  when FunctionDeclaration, FunctionExpression
    obj = YARD::CodeObjects::MethodObject.new(current_yard_class, property.key.val)
    obj.docstring = stripped_comment
  else
    # found a non-method property
  end

  super
end

#with_variables(expr, params = expr.params.map(&:val)) ⇒ Object



87
88
89
90
91
92
93
# File 'lib/parsejs/docs.rb', line 87

def with_variables(expr, params=expr.params.map(&:val))
  locals = FindVars.find_variables(expr)
  @current_variables.push(locals | params)
  yield
ensure
  @current_variables.pop
end