Guest User

Untitled

a guest
Jun 20th, 2018
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.46 KB | None | 0 0
  1. {isValue, notValue, assertType} = require 'sass-lexer/utils'
  2. tokenize = require 'sass-lexer'
  3. path = require 'path'
  4.  
  5. createScope = ->
  6. mixins: []
  7. functions: []
  8. variables: []
  9.  
  10. pushUnique = (arr, val) ->
  11. arr.push val if arr.indexOf(val) is -1
  12.  
  13. # Parse the given module for its external references and top-level declarations.
  14. module.exports = (mod) ->
  15. # TODO: support .sass modules
  16. if mod.ext is '.sass'
  17. throw Error '.sass modules are not supported (yet)'
  18.  
  19. code = mod.content
  20. parser = tokenize code
  21.  
  22. depth = 0 # scope index
  23. scopes = [
  24. createScope() # top-level
  25. ]
  26.  
  27. # external references (variables, functions, mixins)
  28. refs = createScope()
  29.  
  30. # top-level declarations (currently unused)
  31. decls =
  32. mixins: {}
  33. functions: {}
  34. variables: {}
  35.  
  36. # current top-level declaration (currently unused)
  37. decl = null
  38.  
  39. offset = 0 # current char index
  40. prev = null # previous token
  41. curr = null # current token
  42. next = ->
  43. if prev = curr
  44. offset += prev[2]
  45. curr = parser.next()
  46.  
  47. skip = (type) ->
  48. assertType next(), type
  49. next()
  50.  
  51. # Look for the given value in every scope.
  52. search = (key, value) ->
  53. i = depth; while i >= 0
  54. return true if ~scopes[i--][key].indexOf value
  55. return false
  56.  
  57. addReference = (tok) ->
  58. if !search (key = tok[0] + 's'), tok[1]
  59. pushUnique refs[key], tok[1]
  60.  
  61. parseInclude = ->
  62. skip 'space'
  63. if curr and curr[0] is 'identifier'
  64. curr[0] = 'mixin'
  65. addReference curr
  66.  
  67. parseClosure = ->
  68. type = curr[1]
  69. start = offset
  70. console.log type, start
  71. skip 'space'
  72. if curr and curr[0] is 'identifier'
  73. pushUnique scopes[depth][type + 's'], curr[1]
  74. parseArguments scope = createScope()
  75.  
  76. if depth is 0
  77. scope.id = curr[1]
  78. scope.type = type
  79. scope.start = start
  80.  
  81. while next()
  82. if curr[1] is '{'
  83. scopes[++depth] = scope
  84. return
  85.  
  86. parseArguments = (scope) ->
  87.  
  88. if !isValue parser.peek(), '('
  89. return false
  90. next()
  91.  
  92. if isValue parser.peek(), ')'
  93. next()
  94. return true
  95.  
  96. parseList (curr) ->
  97.  
  98. if curr[0] is 'identifier'
  99. # function call
  100. if parseArguments()
  101. curr[0] = 'function'
  102. addReference curr
  103.  
  104. # argument name
  105. else if curr[0] is 'variable'
  106. scope?.variables.push curr[1]
  107. if isValue parser.peek(), ':'
  108. next()
  109. while next()
  110. return if curr[1] is ','
  111. parseExpression curr
  112. return if isValue parser.peek(), ')'
  113.  
  114. parseList = (each) ->
  115. open = 1 # unclosed () pairs
  116. while next()
  117. if curr[1] is '('
  118. open += 1 # maps, lists, and function calls
  119. else if curr[1] is ')'
  120. return true if --open is 0
  121. else each curr
  122. parser.err 'Unexpected end of file'
  123.  
  124. parseInterpolation = ->
  125. while notValue next(), '}'
  126. parseExpression()
  127. return
  128.  
  129. parseBlock = ->
  130. while next()
  131. return if curr[1] is ';'
  132. if curr[1] isnt '{'
  133. parseExpression()
  134. else
  135. scopes[++depth] = createScope()
  136. return
  137.  
  138. parseLoop = ->
  139. declaring = true
  140. scope = createScope()
  141. while next()
  142.  
  143. if curr[1] is '{'
  144. scopes[++depth] = scope
  145. return
  146.  
  147. # variables before "in" are declarations
  148. if declaring
  149. if curr[1] is 'in'
  150. declaring = false
  151. else if curr[0] is 'variable'
  152. scope.variables.push curr[1]
  153.  
  154. # variable reference
  155. else if curr[0] is 'variable'
  156. addReference curr
  157.  
  158. else if curr[0] is 'identifier'
  159. # function call
  160. if parseArguments()
  161. curr[0] = 'function'
  162. addReference curr
  163.  
  164. inSelector = ->
  165. i = -1
  166. while tok = parser.peek ++i
  167. return true if tok[1] is '{'
  168. break if tok[1] is ';'
  169. return false
  170.  
  171. parseExpression = ->
  172.  
  173. # map or list
  174. if curr[1] is '('
  175. return parseList parseExpression
  176.  
  177. # interpolation
  178. if curr[1] is '#' and isValue parser.peek(), '{'
  179. return next() and parseInterpolation()
  180.  
  181. switch curr[0]
  182.  
  183. when 'variable'
  184. # declaration
  185. if isValue parser.peek(), ':'
  186. pushUnique scopes[depth].variables, curr[1]
  187. # continue until the end of declaration
  188. start = offset
  189. parseExpression() while notValue next(), ';'
  190. # top-level declaration
  191. if depth is 0
  192. decls.variables[curr[1]] = code.slice start, offset + 1
  193. # variable reference
  194. else addReference curr
  195.  
  196. when 'identifier'
  197. # bail early for properties
  198. if isValue parser.peek(), ':'
  199. return next()
  200. if inSelector()
  201. # pseudo selector
  202. if isValue parser.peek(), '('
  203. next() and parseList parseExpression
  204. # function call
  205. else if parseArguments()
  206. curr[0] = 'function'
  207. addReference curr
  208.  
  209. while next()
  210.  
  211. if curr[1] is '{'
  212. # enter a new scope
  213. scopes[++depth] = createScope()
  214.  
  215. else if curr[1] is '}'
  216. continue if depth is 0
  217. scope = scopes[depth]
  218. if scope.type
  219. decls[scope.type + 's'][scope.id] =
  220. code.slice scope.start, offset + 1
  221. # exit the current scope
  222. scopes.length = depth--
  223.  
  224. else if curr[0] is 'atrule'
  225. switch curr[1]
  226. when 'include'
  227. parseInclude()
  228. when 'mixin', 'function'
  229. parseClosure()
  230. when 'for', 'each'
  231. parseLoop()
  232. else
  233. parseBlock()
  234.  
  235. else parseExpression()
  236.  
  237. mod.refs = refs
  238. mod.decls = scopes[0]
  239. mod
Add Comment
Please, Sign In to add comment