debug 1.6.3 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CONTRIBUTING.md +19 -7
 - data/Gemfile +0 -0
 - data/LICENSE.txt +0 -0
 - data/README.md +37 -14
 - data/Rakefile +0 -0
 - data/TODO.md +8 -8
 - data/debug.gemspec +1 -1
 - data/exe/rdbg +1 -1
 - data/ext/debug/debug.c +15 -1
 - data/ext/debug/extconf.rb +0 -0
 - data/ext/debug/iseq_collector.c +0 -0
 - data/lib/debug/abbrev_command.rb +77 -0
 - data/lib/debug/breakpoint.rb +17 -11
 - data/lib/debug/client.rb +26 -9
 - data/lib/debug/color.rb +0 -0
 - data/lib/debug/config.rb +34 -16
 - data/lib/debug/console.rb +0 -0
 - data/lib/debug/frame_info.rb +0 -0
 - data/lib/debug/local.rb +16 -10
 - data/lib/debug/open.rb +0 -0
 - data/lib/debug/open_nonstop.rb +0 -0
 - data/lib/debug/prelude.rb +1 -1
 - data/lib/debug/server.rb +25 -21
 - data/lib/debug/server_cdp.rb +292 -86
 - data/lib/debug/server_dap.rb +132 -47
 - data/lib/debug/session.rb +384 -204
 - data/lib/debug/source_repository.rb +39 -19
 - data/lib/debug/start.rb +1 -1
 - data/lib/debug/thread_client.rb +196 -63
 - data/lib/debug/tracer.rb +0 -0
 - data/lib/debug/version.rb +1 -1
 - data/lib/debug.rb +7 -3
 - data/misc/README.md.erb +9 -3
 - metadata +5 -4
 
    
        data/lib/debug/server_cdp.rb
    CHANGED
    
    | 
         @@ -7,13 +7,18 @@ require 'securerandom' 
     | 
|
| 
       7 
7 
     | 
    
         
             
            require 'stringio'
         
     | 
| 
       8 
8 
     | 
    
         
             
            require 'open3'
         
     | 
| 
       9 
9 
     | 
    
         
             
            require 'tmpdir'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'tempfile'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'timeout'
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
            module DEBUGGER__
         
     | 
| 
       12 
14 
     | 
    
         
             
              module UI_CDP
         
     | 
| 
       13 
15 
     | 
    
         
             
                SHOW_PROTOCOL = ENV['RUBY_DEBUG_CDP_SHOW_PROTOCOL'] == '1'
         
     | 
| 
       14 
16 
     | 
    
         | 
| 
      
 17 
     | 
    
         
            +
                class UnsupportedError < StandardError; end
         
     | 
| 
      
 18 
     | 
    
         
            +
                class NotFoundChromeEndpointError < StandardError; end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
       15 
20 
     | 
    
         
             
                class << self
         
     | 
| 
       16 
     | 
    
         
            -
                  def setup_chrome addr
         
     | 
| 
      
 21 
     | 
    
         
            +
                  def setup_chrome addr, uuid
         
     | 
| 
       17 
22 
     | 
    
         
             
                    return if CONFIG[:chrome_path] == ''
         
     | 
| 
       18 
23 
     | 
    
         | 
| 
       19 
24 
     | 
    
         
             
                    port, path, pid = run_new_chrome
         
     | 
| 
         @@ -29,79 +34,218 @@ module DEBUGGER__ 
     | 
|
| 
       29 
34 
     | 
    
         | 
| 
       30 
35 
     | 
    
         
             
                    loop do
         
     | 
| 
       31 
36 
     | 
    
         
             
                      res = ws_client.extract_data
         
     | 
| 
       32 
     | 
    
         
            -
                      case
         
     | 
| 
       33 
     | 
    
         
            -
                      when  
     | 
| 
      
 37 
     | 
    
         
            +
                      case res['id']
         
     | 
| 
      
 38 
     | 
    
         
            +
                      when 1
         
     | 
| 
      
 39 
     | 
    
         
            +
                        target_info = res.dig('result', 'targetInfos')
         
     | 
| 
       34 
40 
     | 
    
         
             
                        page = target_info.find{|t| t['type'] == 'page'}
         
     | 
| 
       35 
41 
     | 
    
         
             
                        ws_client.send id: 2, method: 'Target.attachToTarget',
         
     | 
| 
       36 
42 
     | 
    
         
             
                                      params: {
         
     | 
| 
       37 
43 
     | 
    
         
             
                                        targetId: page['targetId'],
         
     | 
| 
       38 
44 
     | 
    
         
             
                                        flatten: true
         
     | 
| 
       39 
45 
     | 
    
         
             
                                      }
         
     | 
| 
       40 
     | 
    
         
            -
                      when  
     | 
| 
      
 46 
     | 
    
         
            +
                      when 2
         
     | 
| 
       41 
47 
     | 
    
         
             
                        s_id = res.dig('result', 'sessionId')
         
     | 
| 
      
 48 
     | 
    
         
            +
                        # TODO: change id
         
     | 
| 
      
 49 
     | 
    
         
            +
                        ws_client.send sessionId: s_id, id: 100, method: 'Network.enable'
         
     | 
| 
       42 
50 
     | 
    
         
             
                        ws_client.send sessionId: s_id, id: 3,
         
     | 
| 
       43 
51 
     | 
    
         
             
                                      method: 'Page.enable'
         
     | 
| 
       44 
     | 
    
         
            -
                      when  
     | 
| 
      
 52 
     | 
    
         
            +
                      when 3
         
     | 
| 
       45 
53 
     | 
    
         
             
                        s_id = res['sessionId']
         
     | 
| 
       46 
54 
     | 
    
         
             
                        ws_client.send sessionId: s_id, id: 4,
         
     | 
| 
       47 
55 
     | 
    
         
             
                                      method: 'Page.getFrameTree'
         
     | 
| 
       48 
     | 
    
         
            -
                      when  
     | 
| 
      
 56 
     | 
    
         
            +
                      when 4
         
     | 
| 
       49 
57 
     | 
    
         
             
                        s_id = res['sessionId']
         
     | 
| 
       50 
58 
     | 
    
         
             
                        f_id = res.dig('result', 'frameTree', 'frame', 'id')
         
     | 
| 
       51 
59 
     | 
    
         
             
                        ws_client.send sessionId: s_id, id: 5,
         
     | 
| 
       52 
60 
     | 
    
         
             
                                      method: 'Page.navigate',
         
     | 
| 
       53 
61 
     | 
    
         
             
                                      params: {
         
     | 
| 
       54 
     | 
    
         
            -
                                        url: "devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{addr}/#{ 
     | 
| 
      
 62 
     | 
    
         
            +
                                        url: "devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{addr}/#{uuid}",
         
     | 
| 
       55 
63 
     | 
    
         
             
                                        frameId: f_id
         
     | 
| 
       56 
64 
     | 
    
         
             
                                      }
         
     | 
| 
       57 
     | 
    
         
            -
                      when  
     | 
| 
      
 65 
     | 
    
         
            +
                      when 101
         
     | 
| 
       58 
66 
     | 
    
         
             
                        break
         
     | 
| 
      
 67 
     | 
    
         
            +
                      else
         
     | 
| 
      
 68 
     | 
    
         
            +
                        if res['method'] == 'Network.webSocketWillSendHandshakeRequest'
         
     | 
| 
      
 69 
     | 
    
         
            +
                          s_id = res['sessionId']
         
     | 
| 
      
 70 
     | 
    
         
            +
                          # Display the console by entering ESC key
         
     | 
| 
      
 71 
     | 
    
         
            +
                          ws_client.send sessionId: s_id, id: 101,  # TODO: change id
         
     | 
| 
      
 72 
     | 
    
         
            +
                                        method:"Input.dispatchKeyEvent",
         
     | 
| 
      
 73 
     | 
    
         
            +
                                        params: {
         
     | 
| 
      
 74 
     | 
    
         
            +
                                          type:"keyDown",
         
     | 
| 
      
 75 
     | 
    
         
            +
                                          windowsVirtualKeyCode:27 # ESC key
         
     | 
| 
      
 76 
     | 
    
         
            +
                                        }
         
     | 
| 
      
 77 
     | 
    
         
            +
                        end
         
     | 
| 
       59 
78 
     | 
    
         
             
                      end
         
     | 
| 
       60 
79 
     | 
    
         
             
                    end
         
     | 
| 
       61 
80 
     | 
    
         
             
                    pid
         
     | 
| 
       62 
     | 
    
         
            -
                  rescue Errno::ENOENT
         
     | 
| 
      
 81 
     | 
    
         
            +
                  rescue Errno::ENOENT, UnsupportedError, NotFoundChromeEndpointError
         
     | 
| 
       63 
82 
     | 
    
         
             
                    nil
         
     | 
| 
       64 
83 
     | 
    
         
             
                  end
         
     | 
| 
       65 
84 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
                   
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
      
 85 
     | 
    
         
            +
                  TIMEOUT_SEC = 5
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  def run_new_chrome
         
     | 
| 
      
 88 
     | 
    
         
            +
                    path = CONFIG[:chrome_path]
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                    data = nil
         
     | 
| 
      
 91 
     | 
    
         
            +
                    port = nil
         
     | 
| 
      
 92 
     | 
    
         
            +
                    wait_thr = nil
         
     | 
| 
       68 
93 
     | 
    
         | 
| 
       69 
94 
     | 
    
         
             
                    # The process to check OS is based on `selenium` project.
         
     | 
| 
       70 
95 
     | 
    
         
             
                    case RbConfig::CONFIG['host_os']
         
     | 
| 
       71 
96 
     | 
    
         
             
                    when /mswin|msys|mingw|cygwin|emc/
         
     | 
| 
       72 
     | 
    
         
            -
                       
     | 
| 
      
 97 
     | 
    
         
            +
                      if path.nil?
         
     | 
| 
      
 98 
     | 
    
         
            +
                        candidates = ['C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe', 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe']
         
     | 
| 
      
 99 
     | 
    
         
            +
                        path = get_chrome_path candidates
         
     | 
| 
      
 100 
     | 
    
         
            +
                      end
         
     | 
| 
      
 101 
     | 
    
         
            +
                      uuid = SecureRandom.uuid
         
     | 
| 
      
 102 
     | 
    
         
            +
                      # The path is based on https://github.com/sindresorhus/open/blob/v8.4.0/index.js#L128.
         
     | 
| 
      
 103 
     | 
    
         
            +
                      stdin, stdout, stderr, wait_thr = *Open3.popen3("#{ENV['SystemRoot']}\\System32\\WindowsPowerShell\\v1.0\\powershell")
         
     | 
| 
      
 104 
     | 
    
         
            +
                      tf = Tempfile.create(['debug-', '.txt'])
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                      stdin.puts("Start-process '#{path}' -Argumentlist '--remote-debugging-port=0', '--no-first-run', '--no-default-browser-check', '--user-data-dir=C:\\temp' -Wait -RedirectStandardError #{tf.path}")
         
     | 
| 
      
 107 
     | 
    
         
            +
                      stdin.close
         
     | 
| 
      
 108 
     | 
    
         
            +
                      stdout.close
         
     | 
| 
      
 109 
     | 
    
         
            +
                      stderr.close
         
     | 
| 
      
 110 
     | 
    
         
            +
                      port, path = get_devtools_endpoint(tf.path)
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                      at_exit{
         
     | 
| 
      
 113 
     | 
    
         
            +
                        DEBUGGER__.skip_all
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                        stdin, stdout, stderr, wait_thr = *Open3.popen3("#{ENV['SystemRoot']}\\System32\\WindowsPowerShell\\v1.0\\powershell")
         
     | 
| 
      
 116 
     | 
    
         
            +
                        stdin.puts("Stop-process -Name chrome")
         
     | 
| 
      
 117 
     | 
    
         
            +
                        stdin.close
         
     | 
| 
      
 118 
     | 
    
         
            +
                        stdout.close
         
     | 
| 
      
 119 
     | 
    
         
            +
                        stderr.close
         
     | 
| 
      
 120 
     | 
    
         
            +
                        tf.close
         
     | 
| 
      
 121 
     | 
    
         
            +
                        begin
         
     | 
| 
      
 122 
     | 
    
         
            +
                          File.unlink(tf)
         
     | 
| 
      
 123 
     | 
    
         
            +
                        rescue Errno::EACCES
         
     | 
| 
      
 124 
     | 
    
         
            +
                        end
         
     | 
| 
      
 125 
     | 
    
         
            +
                      }
         
     | 
| 
       73 
126 
     | 
    
         
             
                    when /darwin|mac os/
         
     | 
| 
       74 
     | 
    
         
            -
                      '/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome'
         
     | 
| 
      
 127 
     | 
    
         
            +
                      path = path || '/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome'
         
     | 
| 
      
 128 
     | 
    
         
            +
                      dir = Dir.mktmpdir
         
     | 
| 
      
 129 
     | 
    
         
            +
                      # The command line flags are based on: https://developer.mozilla.org/en-US/docs/Tools/Remote_Debugging/Chrome_Desktop#connecting.
         
     | 
| 
      
 130 
     | 
    
         
            +
                      stdin, stdout, stderr, wait_thr = *Open3.popen3("#{path} --remote-debugging-port=0 --no-first-run --no-default-browser-check --user-data-dir=#{dir}")
         
     | 
| 
      
 131 
     | 
    
         
            +
                      stdin.close
         
     | 
| 
      
 132 
     | 
    
         
            +
                      stdout.close
         
     | 
| 
      
 133 
     | 
    
         
            +
                      data = stderr.readpartial 4096
         
     | 
| 
      
 134 
     | 
    
         
            +
                      stderr.close
         
     | 
| 
      
 135 
     | 
    
         
            +
                      if data.match /DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/
         
     | 
| 
      
 136 
     | 
    
         
            +
                        port = $1
         
     | 
| 
      
 137 
     | 
    
         
            +
                        path = $2
         
     | 
| 
      
 138 
     | 
    
         
            +
                      end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                      at_exit{
         
     | 
| 
      
 141 
     | 
    
         
            +
                        DEBUGGER__.skip_all
         
     | 
| 
      
 142 
     | 
    
         
            +
                        FileUtils.rm_rf dir
         
     | 
| 
      
 143 
     | 
    
         
            +
                      }
         
     | 
| 
       75 
144 
     | 
    
         
             
                    when /linux/
         
     | 
| 
       76 
     | 
    
         
            -
                      'google-chrome'
         
     | 
| 
      
 145 
     | 
    
         
            +
                      path = path || 'google-chrome'
         
     | 
| 
      
 146 
     | 
    
         
            +
                      dir = Dir.mktmpdir
         
     | 
| 
      
 147 
     | 
    
         
            +
                      # The command line flags are based on: https://developer.mozilla.org/en-US/docs/Tools/Remote_Debugging/Chrome_Desktop#connecting.
         
     | 
| 
      
 148 
     | 
    
         
            +
                      stdin, stdout, stderr, wait_thr = *Open3.popen3("#{path} --remote-debugging-port=0 --no-first-run --no-default-browser-check --user-data-dir=#{dir}")
         
     | 
| 
      
 149 
     | 
    
         
            +
                      stdin.close
         
     | 
| 
      
 150 
     | 
    
         
            +
                      stdout.close
         
     | 
| 
      
 151 
     | 
    
         
            +
                      data = ''
         
     | 
| 
      
 152 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 153 
     | 
    
         
            +
                        Timeout.timeout(TIMEOUT_SEC) do
         
     | 
| 
      
 154 
     | 
    
         
            +
                          until data.match?(/DevTools listening on ws:\/\/127.0.0.1:\d+.*/)
         
     | 
| 
      
 155 
     | 
    
         
            +
                            data = stderr.readpartial 4096
         
     | 
| 
      
 156 
     | 
    
         
            +
                          end
         
     | 
| 
      
 157 
     | 
    
         
            +
                        end
         
     | 
| 
      
 158 
     | 
    
         
            +
                      rescue Exception
         
     | 
| 
      
 159 
     | 
    
         
            +
                        raise NotFoundChromeEndpointError
         
     | 
| 
      
 160 
     | 
    
         
            +
                      end
         
     | 
| 
      
 161 
     | 
    
         
            +
                      stderr.close
         
     | 
| 
      
 162 
     | 
    
         
            +
                      if data.match /DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/
         
     | 
| 
      
 163 
     | 
    
         
            +
                        port = $1
         
     | 
| 
      
 164 
     | 
    
         
            +
                        path = $2
         
     | 
| 
      
 165 
     | 
    
         
            +
                      end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                      at_exit{
         
     | 
| 
      
 168 
     | 
    
         
            +
                        DEBUGGER__.skip_all
         
     | 
| 
      
 169 
     | 
    
         
            +
                        FileUtils.rm_rf dir
         
     | 
| 
      
 170 
     | 
    
         
            +
                      }
         
     | 
| 
       77 
171 
     | 
    
         
             
                    else
         
     | 
| 
       78 
     | 
    
         
            -
                      raise  
     | 
| 
      
 172 
     | 
    
         
            +
                      raise UnsupportedError
         
     | 
| 
       79 
173 
     | 
    
         
             
                    end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                    [port, path, wait_thr.pid]
         
     | 
| 
       80 
176 
     | 
    
         
             
                  end
         
     | 
| 
       81 
177 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
                  def  
     | 
| 
       83 
     | 
    
         
            -
                     
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
                     
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
      
 178 
     | 
    
         
            +
                  def get_chrome_path candidates
         
     | 
| 
      
 179 
     | 
    
         
            +
                    candidates.each{|c|
         
     | 
| 
      
 180 
     | 
    
         
            +
                      if File.exist? c
         
     | 
| 
      
 181 
     | 
    
         
            +
                        return c
         
     | 
| 
      
 182 
     | 
    
         
            +
                      end
         
     | 
| 
      
 183 
     | 
    
         
            +
                    }
         
     | 
| 
      
 184 
     | 
    
         
            +
                    raise UnsupportedError
         
     | 
| 
      
 185 
     | 
    
         
            +
                  end
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
                  ITERATIONS = 50
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                  def get_devtools_endpoint tf
         
     | 
| 
      
 190 
     | 
    
         
            +
                    i = 1
         
     | 
| 
      
 191 
     | 
    
         
            +
                    while i < ITERATIONS
         
     | 
| 
      
 192 
     | 
    
         
            +
                      i += 1
         
     | 
| 
      
 193 
     | 
    
         
            +
                      if File.exist?(tf) && data = File.read(tf)
         
     | 
| 
      
 194 
     | 
    
         
            +
                        if data.match /DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/
         
     | 
| 
      
 195 
     | 
    
         
            +
                          port = $1
         
     | 
| 
      
 196 
     | 
    
         
            +
                          path = $2
         
     | 
| 
      
 197 
     | 
    
         
            +
                          return [port, path]
         
     | 
| 
      
 198 
     | 
    
         
            +
                        end
         
     | 
| 
      
 199 
     | 
    
         
            +
                      end
         
     | 
| 
      
 200 
     | 
    
         
            +
                      sleep 0.1
         
     | 
| 
       93 
201 
     | 
    
         
             
                    end
         
     | 
| 
       94 
     | 
    
         
            -
                     
     | 
| 
      
 202 
     | 
    
         
            +
                    raise NotFoundChromeEndpointError
         
     | 
| 
      
 203 
     | 
    
         
            +
                  end
         
     | 
| 
      
 204 
     | 
    
         
            +
                end
         
     | 
| 
       95 
205 
     | 
    
         | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
      
 206 
     | 
    
         
            +
                def send_chrome_response req
         
     | 
| 
      
 207 
     | 
    
         
            +
                  @repl = false
         
     | 
| 
      
 208 
     | 
    
         
            +
                  case req
         
     | 
| 
      
 209 
     | 
    
         
            +
                  when /^GET\s\/json\/version\sHTTP\/1.1/
         
     | 
| 
      
 210 
     | 
    
         
            +
                    body = {
         
     | 
| 
      
 211 
     | 
    
         
            +
                      Browser: "ruby/v#{RUBY_VERSION}",
         
     | 
| 
      
 212 
     | 
    
         
            +
                      'Protocol-Version': "1.1"
         
     | 
| 
       99 
213 
     | 
    
         
             
                    }
         
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
                     
     | 
| 
      
 214 
     | 
    
         
            +
                    send_http_res body
         
     | 
| 
      
 215 
     | 
    
         
            +
                    raise UI_ServerBase::RetryConnection
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
                  when /^GET\s\/json\sHTTP\/1.1/
         
     | 
| 
      
 218 
     | 
    
         
            +
                    @uuid = @uuid || SecureRandom.uuid
         
     | 
| 
      
 219 
     | 
    
         
            +
                    addr = @local_addr.inspect_sockaddr
         
     | 
| 
      
 220 
     | 
    
         
            +
                    body = [{
         
     | 
| 
      
 221 
     | 
    
         
            +
                      description: "ruby instance",
         
     | 
| 
      
 222 
     | 
    
         
            +
                      devtoolsFrontendUrl: "devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=#{addr}/#{@uuid}",
         
     | 
| 
      
 223 
     | 
    
         
            +
                      id: @uuid,
         
     | 
| 
      
 224 
     | 
    
         
            +
                      title: $0,
         
     | 
| 
      
 225 
     | 
    
         
            +
                      type: "node",
         
     | 
| 
      
 226 
     | 
    
         
            +
                      url: "file://#{File.absolute_path($0)}",
         
     | 
| 
      
 227 
     | 
    
         
            +
                      webSocketDebuggerUrl: "ws://#{addr}/#{@uuid}"
         
     | 
| 
      
 228 
     | 
    
         
            +
                    }]
         
     | 
| 
      
 229 
     | 
    
         
            +
                    send_http_res body
         
     | 
| 
      
 230 
     | 
    
         
            +
                    raise UI_ServerBase::RetryConnection
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
                  when /^GET\s\/(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})\sHTTP\/1.1/
         
     | 
| 
      
 233 
     | 
    
         
            +
                    raise 'Incorrect uuid' unless $1 == @uuid
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
                    @need_pause_at_first = false
         
     | 
| 
      
 236 
     | 
    
         
            +
                    CONFIG.set_config no_color: true
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
                    @ws_server = WebSocketServer.new(@sock)
         
     | 
| 
      
 239 
     | 
    
         
            +
                    @ws_server.handshake
         
     | 
| 
       102 
240 
     | 
    
         
             
                  end
         
     | 
| 
       103 
241 
     | 
    
         
             
                end
         
     | 
| 
       104 
242 
     | 
    
         | 
| 
      
 243 
     | 
    
         
            +
                def send_http_res body
         
     | 
| 
      
 244 
     | 
    
         
            +
                  json = JSON.generate body
         
     | 
| 
      
 245 
     | 
    
         
            +
                  header = "HTTP/1.0 200 OK\r\nContent-Type: application/json; charset=UTF-8\r\nCache-Control: no-cache\r\nContent-Length: #{json.bytesize}\r\n\r\n"
         
     | 
| 
      
 246 
     | 
    
         
            +
                  @sock.puts "#{header}#{json}"
         
     | 
| 
      
 247 
     | 
    
         
            +
                end
         
     | 
| 
      
 248 
     | 
    
         
            +
             
     | 
| 
       105 
249 
     | 
    
         
             
                module WebSocketUtils
         
     | 
| 
       106 
250 
     | 
    
         
             
                  class Frame
         
     | 
| 
       107 
251 
     | 
    
         
             
                    attr_reader :b
         
     | 
| 
         @@ -528,12 +672,6 @@ module DEBUGGER__ 
     | 
|
| 
       528 
672 
     | 
    
         | 
| 
       529 
673 
     | 
    
         
             
                ## Called by the SESSION thread
         
     | 
| 
       530 
674 
     | 
    
         | 
| 
       531 
     | 
    
         
            -
                def readline prompt
         
     | 
| 
       532 
     | 
    
         
            -
                  return 'c' unless @q_msg
         
     | 
| 
       533 
     | 
    
         
            -
             
     | 
| 
       534 
     | 
    
         
            -
                  @q_msg.pop || 'kill!'
         
     | 
| 
       535 
     | 
    
         
            -
                end
         
     | 
| 
       536 
     | 
    
         
            -
             
     | 
| 
       537 
675 
     | 
    
         
             
                def respond req, **result
         
     | 
| 
       538 
676 
     | 
    
         
             
                  send_response req, **result
         
     | 
| 
       539 
677 
     | 
    
         
             
                end
         
     | 
| 
         @@ -561,6 +699,30 @@ module DEBUGGER__ 
     | 
|
| 
       561 
699 
     | 
    
         
             
              end
         
     | 
| 
       562 
700 
     | 
    
         | 
| 
       563 
701 
     | 
    
         
             
              class Session
         
     | 
| 
      
 702 
     | 
    
         
            +
                include GlobalVariablesHelper
         
     | 
| 
      
 703 
     | 
    
         
            +
             
     | 
| 
      
 704 
     | 
    
         
            +
                # FIXME: unify this method with ThreadClient#propertyDescriptor.
         
     | 
| 
      
 705 
     | 
    
         
            +
                def get_type obj
         
     | 
| 
      
 706 
     | 
    
         
            +
                  case obj
         
     | 
| 
      
 707 
     | 
    
         
            +
                  when Array
         
     | 
| 
      
 708 
     | 
    
         
            +
                    ['object', 'array']
         
     | 
| 
      
 709 
     | 
    
         
            +
                  when Hash
         
     | 
| 
      
 710 
     | 
    
         
            +
                    ['object', 'map']
         
     | 
| 
      
 711 
     | 
    
         
            +
                  when String
         
     | 
| 
      
 712 
     | 
    
         
            +
                    ['string']
         
     | 
| 
      
 713 
     | 
    
         
            +
                  when TrueClass, FalseClass
         
     | 
| 
      
 714 
     | 
    
         
            +
                    ['boolean']
         
     | 
| 
      
 715 
     | 
    
         
            +
                  when Symbol
         
     | 
| 
      
 716 
     | 
    
         
            +
                    ['symbol']
         
     | 
| 
      
 717 
     | 
    
         
            +
                  when Integer, Float
         
     | 
| 
      
 718 
     | 
    
         
            +
                    ['number']
         
     | 
| 
      
 719 
     | 
    
         
            +
                  when Exception
         
     | 
| 
      
 720 
     | 
    
         
            +
                    ['object', 'error']
         
     | 
| 
      
 721 
     | 
    
         
            +
                  else
         
     | 
| 
      
 722 
     | 
    
         
            +
                    ['object']
         
     | 
| 
      
 723 
     | 
    
         
            +
                  end
         
     | 
| 
      
 724 
     | 
    
         
            +
                end
         
     | 
| 
      
 725 
     | 
    
         
            +
             
     | 
| 
       564 
726 
     | 
    
         
             
                def fail_response req, **result
         
     | 
| 
       565 
727 
     | 
    
         
             
                  @ui.respond_fail req, **result
         
     | 
| 
       566 
728 
     | 
    
         
             
                  return :retry
         
     | 
| 
         @@ -584,17 +746,38 @@ module DEBUGGER__ 
     | 
|
| 
       584 
746 
     | 
    
         
             
                                    code: INVALID_PARAMS,
         
     | 
| 
       585 
747 
     | 
    
         
             
                                    message: "'callFrameId' is an invalid"
         
     | 
| 
       586 
748 
     | 
    
         
             
                    end
         
     | 
| 
       587 
     | 
    
         
            -
                  when 'Runtime.getProperties'
         
     | 
| 
       588 
     | 
    
         
            -
                    oid = req.dig('params', 'objectId')
         
     | 
| 
      
 749 
     | 
    
         
            +
                  when 'Runtime.getProperties', 'Runtime.getExceptionDetails'
         
     | 
| 
      
 750 
     | 
    
         
            +
                    oid = req.dig('params', 'objectId') || req.dig('params', 'errorObjectId')
         
     | 
| 
       589 
751 
     | 
    
         
             
                    if ref = @obj_map[oid]
         
     | 
| 
       590 
752 
     | 
    
         
             
                      case ref[0]
         
     | 
| 
       591 
753 
     | 
    
         
             
                      when 'local'
         
     | 
| 
       592 
754 
     | 
    
         
             
                        frame_id = ref[1]
         
     | 
| 
       593 
755 
     | 
    
         
             
                        fid = @frame_map[frame_id]
         
     | 
| 
       594 
756 
     | 
    
         
             
                        request_tc [:cdp, :scope, req, fid]
         
     | 
| 
      
 757 
     | 
    
         
            +
                      when 'global'
         
     | 
| 
      
 758 
     | 
    
         
            +
                        vars = safe_global_variables.sort.map do |name|
         
     | 
| 
      
 759 
     | 
    
         
            +
                          gv = eval(name.to_s)
         
     | 
| 
      
 760 
     | 
    
         
            +
                          prop = {
         
     | 
| 
      
 761 
     | 
    
         
            +
                            name: name,
         
     | 
| 
      
 762 
     | 
    
         
            +
                            value: {
         
     | 
| 
      
 763 
     | 
    
         
            +
                              description: gv.inspect
         
     | 
| 
      
 764 
     | 
    
         
            +
                            },
         
     | 
| 
      
 765 
     | 
    
         
            +
                            configurable: true,
         
     | 
| 
      
 766 
     | 
    
         
            +
                            enumerable: true
         
     | 
| 
      
 767 
     | 
    
         
            +
                          }
         
     | 
| 
      
 768 
     | 
    
         
            +
                          type, subtype = get_type(gv)
         
     | 
| 
      
 769 
     | 
    
         
            +
                          prop[:value][:type] = type
         
     | 
| 
      
 770 
     | 
    
         
            +
                          prop[:value][:subtype] = subtype if subtype
         
     | 
| 
      
 771 
     | 
    
         
            +
                          prop
         
     | 
| 
      
 772 
     | 
    
         
            +
                        end
         
     | 
| 
      
 773 
     | 
    
         
            +
             
     | 
| 
      
 774 
     | 
    
         
            +
                        @ui.respond req, result: vars
         
     | 
| 
      
 775 
     | 
    
         
            +
                        return :retry
         
     | 
| 
       595 
776 
     | 
    
         
             
                      when 'properties'
         
     | 
| 
       596 
777 
     | 
    
         
             
                        request_tc [:cdp, :properties, req, oid]
         
     | 
| 
       597 
     | 
    
         
            -
                      when ' 
     | 
| 
      
 778 
     | 
    
         
            +
                      when 'exception'
         
     | 
| 
      
 779 
     | 
    
         
            +
                        request_tc [:cdp, :exception, req, oid]
         
     | 
| 
      
 780 
     | 
    
         
            +
                      when 'script'
         
     | 
| 
       598 
781 
     | 
    
         
             
                        # TODO: Support script and global types
         
     | 
| 
       599 
782 
     | 
    
         
             
                        @ui.respond req, result: []
         
     | 
| 
       600 
783 
     | 
    
         
             
                        return :retry
         
     | 
| 
         @@ -730,6 +913,9 @@ module DEBUGGER__ 
     | 
|
| 
       730 
913 
     | 
    
         
             
                            frame[:scriptId] = s_id
         
     | 
| 
       731 
914 
     | 
    
         
             
                          end
         
     | 
| 
       732 
915 
     | 
    
         
             
                        }
         
     | 
| 
      
 916 
     | 
    
         
            +
                        if oid = exc[:exception][:objectId]
         
     | 
| 
      
 917 
     | 
    
         
            +
                          @obj_map[oid] = ['exception']
         
     | 
| 
      
 918 
     | 
    
         
            +
                        end
         
     | 
| 
       733 
919 
     | 
    
         
             
                      end
         
     | 
| 
       734 
920 
     | 
    
         
             
                      rs = result.dig(:response, :result)
         
     | 
| 
       735 
921 
     | 
    
         
             
                      [rs].each{|obj|
         
     | 
| 
         @@ -767,6 +953,8 @@ module DEBUGGER__ 
     | 
|
| 
       767 
953 
     | 
    
         
             
                      }
         
     | 
| 
       768 
954 
     | 
    
         
             
                    }
         
     | 
| 
       769 
955 
     | 
    
         
             
                    @ui.respond req, **result
         
     | 
| 
      
 956 
     | 
    
         
            +
                  when :exception
         
     | 
| 
      
 957 
     | 
    
         
            +
                    @ui.respond req, **result
         
     | 
| 
       770 
958 
     | 
    
         
             
                  end
         
     | 
| 
       771 
959 
     | 
    
         
             
                end
         
     | 
| 
       772 
960 
     | 
    
         
             
              end
         
     | 
| 
         @@ -857,7 +1045,7 @@ module DEBUGGER__ 
     | 
|
| 
       857 
1045 
     | 
    
         
             
                        case expr
         
     | 
| 
       858 
1046 
     | 
    
         
             
                        # Chrome doesn't read instance variables
         
     | 
| 
       859 
1047 
     | 
    
         
             
                        when /\A\$\S/
         
     | 
| 
       860 
     | 
    
         
            -
                           
     | 
| 
      
 1048 
     | 
    
         
            +
                          safe_global_variables.each{|gvar|
         
     | 
| 
       861 
1049 
     | 
    
         
             
                            if gvar.to_s == expr
         
     | 
| 
       862 
1050 
     | 
    
         
             
                              result = eval(gvar.to_s)
         
     | 
| 
       863 
1051 
     | 
    
         
             
                              break false
         
     | 
| 
         @@ -872,8 +1060,8 @@ module DEBUGGER__ 
     | 
|
| 
       872 
1060 
     | 
    
         
             
                            result = b.local_variable_get(expr)
         
     | 
| 
       873 
1061 
     | 
    
         
             
                          rescue NameError
         
     | 
| 
       874 
1062 
     | 
    
         
             
                            # try to check method
         
     | 
| 
       875 
     | 
    
         
            -
                            if b.receiver 
     | 
| 
       876 
     | 
    
         
            -
                              result = b.receiver 
     | 
| 
      
 1063 
     | 
    
         
            +
                            if M_RESPOND_TO_P.bind_call(b.receiver, expr, include_all: true)
         
     | 
| 
      
 1064 
     | 
    
         
            +
                              result = M_METHOD.bind_call(b.receiver, expr)
         
     | 
| 
       877 
1065 
     | 
    
         
             
                            else
         
     | 
| 
       878 
1066 
     | 
    
         
             
                              message = "Error: Can not evaluate: #{expr.inspect}"
         
     | 
| 
       879 
1067 
     | 
    
         
             
                            end
         
     | 
| 
         @@ -886,35 +1074,7 @@ module DEBUGGER__ 
     | 
|
| 
       886 
1074 
     | 
    
         
             
                          result = current_frame.binding.eval(expr.to_s, '(DEBUG CONSOLE)')
         
     | 
| 
       887 
1075 
     | 
    
         
             
                        rescue Exception => e
         
     | 
| 
       888 
1076 
     | 
    
         
             
                          result = e
         
     | 
| 
       889 
     | 
    
         
            -
                           
     | 
| 
       890 
     | 
    
         
            -
                          frames = [
         
     | 
| 
       891 
     | 
    
         
            -
                            {
         
     | 
| 
       892 
     | 
    
         
            -
                              columnNumber: 0,
         
     | 
| 
       893 
     | 
    
         
            -
                              functionName: 'eval',
         
     | 
| 
       894 
     | 
    
         
            -
                              lineNumber: 0,
         
     | 
| 
       895 
     | 
    
         
            -
                              url: ''
         
     | 
| 
       896 
     | 
    
         
            -
                            }
         
     | 
| 
       897 
     | 
    
         
            -
                          ]
         
     | 
| 
       898 
     | 
    
         
            -
                          e.backtrace_locations&.each do |loc|
         
     | 
| 
       899 
     | 
    
         
            -
                            break if loc.path == __FILE__
         
     | 
| 
       900 
     | 
    
         
            -
                            path = loc.absolute_path || loc.path
         
     | 
| 
       901 
     | 
    
         
            -
                            frames << {
         
     | 
| 
       902 
     | 
    
         
            -
                              columnNumber: 0,
         
     | 
| 
       903 
     | 
    
         
            -
                              functionName: loc.base_label,
         
     | 
| 
       904 
     | 
    
         
            -
                              lineNumber: loc.lineno - 1,
         
     | 
| 
       905 
     | 
    
         
            -
                              url: path
         
     | 
| 
       906 
     | 
    
         
            -
                            }
         
     | 
| 
       907 
     | 
    
         
            -
                          end
         
     | 
| 
       908 
     | 
    
         
            -
                          res[:exceptionDetails] = {
         
     | 
| 
       909 
     | 
    
         
            -
                            exceptionId: 1,
         
     | 
| 
       910 
     | 
    
         
            -
                            text: 'Uncaught',
         
     | 
| 
       911 
     | 
    
         
            -
                            lineNumber: 0,
         
     | 
| 
       912 
     | 
    
         
            -
                            columnNumber: 0,
         
     | 
| 
       913 
     | 
    
         
            -
                            exception: evaluate_result(result),
         
     | 
| 
       914 
     | 
    
         
            -
                            stackTrace: {
         
     | 
| 
       915 
     | 
    
         
            -
                              callFrames: frames
         
     | 
| 
       916 
     | 
    
         
            -
                            }
         
     | 
| 
       917 
     | 
    
         
            -
                          }
         
     | 
| 
      
 1077 
     | 
    
         
            +
                          res[:exceptionDetails] = exceptionDetails(e, 'Uncaught')
         
     | 
| 
       918 
1078 
     | 
    
         
             
                        ensure
         
     | 
| 
       919 
1079 
     | 
    
         
             
                          output = $stdout.string
         
     | 
| 
       920 
1080 
     | 
    
         
             
                          $stdout = orig_stdout
         
     | 
| 
         @@ -987,13 +1147,51 @@ module DEBUGGER__ 
     | 
|
| 
       987 
1147 
     | 
    
         
             
                        ]
         
     | 
| 
       988 
1148 
     | 
    
         
             
                      end
         
     | 
| 
       989 
1149 
     | 
    
         | 
| 
       990 
     | 
    
         
            -
                      result += obj. 
     | 
| 
       991 
     | 
    
         
            -
                        variable(iv,  
     | 
| 
      
 1150 
     | 
    
         
            +
                      result += M_INSTANCE_VARIABLES.bind_call(obj).map{|iv|
         
     | 
| 
      
 1151 
     | 
    
         
            +
                        variable(iv, M_INSTANCE_VARIABLE_GET.bind_call(obj, iv))
         
     | 
| 
       992 
1152 
     | 
    
         
             
                      }
         
     | 
| 
       993 
     | 
    
         
            -
                      prop += [internalProperty('#class', obj 
     | 
| 
      
 1153 
     | 
    
         
            +
                      prop += [internalProperty('#class', M_CLASS.bind_call(obj))]
         
     | 
| 
       994 
1154 
     | 
    
         
             
                    end
         
     | 
| 
       995 
1155 
     | 
    
         
             
                    event! :cdp_result, :properties, req, result: result, internalProperties: prop
         
     | 
| 
      
 1156 
     | 
    
         
            +
                  when :exception
         
     | 
| 
      
 1157 
     | 
    
         
            +
                    oid = args.shift
         
     | 
| 
      
 1158 
     | 
    
         
            +
                    exc = nil
         
     | 
| 
      
 1159 
     | 
    
         
            +
                    if obj = @obj_map[oid]
         
     | 
| 
      
 1160 
     | 
    
         
            +
                      exc = exceptionDetails obj, obj.to_s
         
     | 
| 
      
 1161 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1162 
     | 
    
         
            +
                    event! :cdp_result, :exception, req, exceptionDetails: exc
         
     | 
| 
      
 1163 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1164 
     | 
    
         
            +
                end
         
     | 
| 
      
 1165 
     | 
    
         
            +
             
     | 
| 
      
 1166 
     | 
    
         
            +
                def exceptionDetails exc, text
         
     | 
| 
      
 1167 
     | 
    
         
            +
                  frames = [
         
     | 
| 
      
 1168 
     | 
    
         
            +
                    {
         
     | 
| 
      
 1169 
     | 
    
         
            +
                      columnNumber: 0,
         
     | 
| 
      
 1170 
     | 
    
         
            +
                      functionName: 'eval',
         
     | 
| 
      
 1171 
     | 
    
         
            +
                      lineNumber: 0,
         
     | 
| 
      
 1172 
     | 
    
         
            +
                      url: ''
         
     | 
| 
      
 1173 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1174 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 1175 
     | 
    
         
            +
                  exc.backtrace_locations&.each do |loc|
         
     | 
| 
      
 1176 
     | 
    
         
            +
                    break if loc.path == __FILE__
         
     | 
| 
      
 1177 
     | 
    
         
            +
                    path = loc.absolute_path || loc.path
         
     | 
| 
      
 1178 
     | 
    
         
            +
                    frames << {
         
     | 
| 
      
 1179 
     | 
    
         
            +
                      columnNumber: 0,
         
     | 
| 
      
 1180 
     | 
    
         
            +
                      functionName: loc.base_label,
         
     | 
| 
      
 1181 
     | 
    
         
            +
                      lineNumber: loc.lineno - 1,
         
     | 
| 
      
 1182 
     | 
    
         
            +
                      url: path
         
     | 
| 
      
 1183 
     | 
    
         
            +
                    }
         
     | 
| 
       996 
1184 
     | 
    
         
             
                  end
         
     | 
| 
      
 1185 
     | 
    
         
            +
                  {
         
     | 
| 
      
 1186 
     | 
    
         
            +
                    exceptionId: 1,
         
     | 
| 
      
 1187 
     | 
    
         
            +
                    text: text,
         
     | 
| 
      
 1188 
     | 
    
         
            +
                    lineNumber: 0,
         
     | 
| 
      
 1189 
     | 
    
         
            +
                    columnNumber: 0,
         
     | 
| 
      
 1190 
     | 
    
         
            +
                    exception: evaluate_result(exc),
         
     | 
| 
      
 1191 
     | 
    
         
            +
                    stackTrace: {
         
     | 
| 
      
 1192 
     | 
    
         
            +
                      callFrames: frames
         
     | 
| 
      
 1193 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1194 
     | 
    
         
            +
                  }
         
     | 
| 
       997 
1195 
     | 
    
         
             
                end
         
     | 
| 
       998 
1196 
     | 
    
         | 
| 
       999 
1197 
     | 
    
         
             
                def search_const b, expr
         
     | 
| 
         @@ -1001,7 +1199,11 @@ module DEBUGGER__ 
     | 
|
| 
       1001 
1199 
     | 
    
         
             
                  [Object, *b.eval('::Module.nesting')].reverse_each{|mod|
         
     | 
| 
       1002 
1200 
     | 
    
         
             
                    if cs.all?{|c|
         
     | 
| 
       1003 
1201 
     | 
    
         
             
                         if mod.const_defined?(c)
         
     | 
| 
       1004 
     | 
    
         
            -
                            
     | 
| 
      
 1202 
     | 
    
         
            +
                           begin
         
     | 
| 
      
 1203 
     | 
    
         
            +
                             mod = mod.const_get(c)
         
     | 
| 
      
 1204 
     | 
    
         
            +
                           rescue Exception
         
     | 
| 
      
 1205 
     | 
    
         
            +
                             false
         
     | 
| 
      
 1206 
     | 
    
         
            +
                           end
         
     | 
| 
       1005 
1207 
     | 
    
         
             
                         else
         
     | 
| 
       1006 
1208 
     | 
    
         
             
                           false
         
     | 
| 
       1007 
1209 
     | 
    
         
             
                         end
         
     | 
| 
         @@ -1045,25 +1247,29 @@ module DEBUGGER__ 
     | 
|
| 
       1045 
1247 
     | 
    
         
             
                    v = prop[:value]
         
     | 
| 
       1046 
1248 
     | 
    
         
             
                    v.delete :value
         
     | 
| 
       1047 
1249 
     | 
    
         
             
                    v[:subtype] = subtype if subtype
         
     | 
| 
       1048 
     | 
    
         
            -
                    v[:className] = obj. 
     | 
| 
      
 1250 
     | 
    
         
            +
                    v[:className] = (klass = M_CLASS.bind_call(obj)).name || klass.to_s
         
     | 
| 
       1049 
1251 
     | 
    
         
             
                  end
         
     | 
| 
       1050 
1252 
     | 
    
         
             
                  prop
         
     | 
| 
       1051 
1253 
     | 
    
         
             
                end
         
     | 
| 
       1052 
1254 
     | 
    
         | 
| 
       1053 
1255 
     | 
    
         
             
                def preview_ value, hash, overflow
         
     | 
| 
      
 1256 
     | 
    
         
            +
                  # The reason for not using "map" method is to prevent the object overriding it from causing bugs.
         
     | 
| 
      
 1257 
     | 
    
         
            +
                  # https://github.com/ruby/debug/issues/781
         
     | 
| 
      
 1258 
     | 
    
         
            +
                  props = []
         
     | 
| 
      
 1259 
     | 
    
         
            +
                  hash.each{|k, v|
         
     | 
| 
      
 1260 
     | 
    
         
            +
                    pd = propertyDescriptor k, v
         
     | 
| 
      
 1261 
     | 
    
         
            +
                    props << {
         
     | 
| 
      
 1262 
     | 
    
         
            +
                      name: pd[:name],
         
     | 
| 
      
 1263 
     | 
    
         
            +
                      type: pd[:value][:type],
         
     | 
| 
      
 1264 
     | 
    
         
            +
                      value: pd[:value][:description]
         
     | 
| 
      
 1265 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1266 
     | 
    
         
            +
                  }
         
     | 
| 
       1054 
1267 
     | 
    
         
             
                  {
         
     | 
| 
       1055 
1268 
     | 
    
         
             
                    type: value[:type],
         
     | 
| 
       1056 
1269 
     | 
    
         
             
                    subtype: value[:subtype],
         
     | 
| 
       1057 
1270 
     | 
    
         
             
                    description: value[:description],
         
     | 
| 
       1058 
1271 
     | 
    
         
             
                    overflow: overflow,
         
     | 
| 
       1059 
     | 
    
         
            -
                    properties:  
     | 
| 
       1060 
     | 
    
         
            -
                      pd = propertyDescriptor k, v
         
     | 
| 
       1061 
     | 
    
         
            -
                      {
         
     | 
| 
       1062 
     | 
    
         
            -
                        name: pd[:name],
         
     | 
| 
       1063 
     | 
    
         
            -
                        type: pd[:value][:type],
         
     | 
| 
       1064 
     | 
    
         
            -
                        value: pd[:value][:description]
         
     | 
| 
       1065 
     | 
    
         
            -
                      }
         
     | 
| 
       1066 
     | 
    
         
            -
                    }
         
     | 
| 
      
 1272 
     | 
    
         
            +
                    properties: props
         
     | 
| 
       1067 
1273 
     | 
    
         
             
                  }
         
     | 
| 
       1068 
1274 
     | 
    
         
             
                end
         
     | 
| 
       1069 
1275 
     | 
    
         |