   # [4] {val} {cs escaped}
   # [5] val bare
   # [6] whitespace
-  TAG_ATTRIBUTES = /(?:([-A-Za-z0-9_]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|(?:{((?:\\.|[\s\S])*)})|([^>\s]+)))?)|([\s\n]+)/g
+  TAG_ATTRIBUTES = ///
+    (?:
+      ([-A-Za-z0-9_]+) # attr name (captured)
+      (?:
+        \s*=\s* # equals and whitespace
+        (?:
+            (?: " ( (?: \\. | [^"] )* ) " ) # double quoted value (captured)
+          | (?: ' ( (?: \\. | [^'] )* ) ' ) # single quoted value (captured)
+          | (?: { ( (?: \\. | [\s\S] )* ) } ) # cjsx escaped expression (captured)
+          | ( [^>\s]+ ) # bare value (captured)
+        )
+      )?
+    )
+    | ( [\s\n]+ ) # whitespace (captured)
+  ///g
 
 PRAGMA = /^\s*#\s*@cjsx\s+(\S*)/i
 


  # fallthrough
  coffeescriptCode: ->
    # return 0 unless @activeBranchNode().type is $.ROOT or @activeBranchNode().type is $.CJSX_ESC
    
    unless @newestNode().type is $.CS
      @addLeafNodeToActiveBranch parseTreeLeafNode $.CS, '' # init value as string

# [1] tag name
# [2] attributes text
# [3] self closing?
OPENING_TAG = /// ^
  <
    ([-A-Za-z0-9_]+) # tag name (captured)
    (
      (?:\s+[\w-]+ # attr name
        (?:\s*=\s* # equals and whitespace
          (?:
              (?:"[^"]*") # double quoted value
            | (?:'[^']*') # single quoted value
            | (?:{[\s\S]*?}) # cjsx escaped expression
            | [^>\s]+ # bare value
          ) 
        )?
      )*?
      \s* # whitespace after attr pair
    ) # attributes text (captured)
    (\/?) # self closing? (captured)
  >
///

# [1] tag name
CLOSING_TAG = /^<\/([-A-Za-z0-9_]+)[^>]*>/
