index.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /**
  2. * util-deps.js - The parser for dependencies
  3. * ref: tests/research/parse-dependencies/test.html
  4. * ref: https://github.com/seajs/crequire
  5. */
  6. function parseDependencies(s, replace, includeAsync) {
  7. if(replace === true) {
  8. includeAsync = true;
  9. replace = null;
  10. }
  11. if(s.indexOf('require') == -1 && s.indexOf('import') == -1) {
  12. return replace ? s : [];
  13. }
  14. var index = 0, peek, length = s.length, isReg = 1, modName = 0, res = []
  15. var parentheseState = 0, parentheseStack = []
  16. var braceState, braceStack = [], isReturn
  17. var last
  18. var flag
  19. var quote
  20. while(index < length) {
  21. readch()
  22. if(isBlank()) {
  23. if(isReturn && (peek == '\n' || peek == '\r')) {
  24. braceState = 0
  25. isReturn = 0
  26. }
  27. }
  28. else if(isQuote()) {
  29. dealQuote()
  30. isReg = 1
  31. isReturn = 0
  32. braceState = 0
  33. }
  34. else if(peek == '/') {
  35. readch()
  36. if(peek == '/') {
  37. index = s.indexOf('\n', index)
  38. if(index == -1) {
  39. index = s.length
  40. }
  41. }
  42. else if(peek == '*') {
  43. var i = s.indexOf('\n', index)
  44. index = s.indexOf('*/', index)
  45. if(index == -1) {
  46. index = length
  47. }
  48. else {
  49. index += 2
  50. }
  51. if(isReturn && i != -1 && i < index) {
  52. braceState = 0
  53. isReturn = 0
  54. }
  55. }
  56. else if(isReg) {
  57. dealReg()
  58. isReg = 0
  59. isReturn = 0
  60. braceState = 0
  61. }
  62. else {
  63. index--
  64. isReg = 1
  65. isReturn = 0
  66. braceState = 1
  67. }
  68. }
  69. else if(isWord()) {
  70. dealWord()
  71. }
  72. else if(isNumber()) {
  73. dealNumber()
  74. isReturn = 0
  75. braceState = 0
  76. }
  77. else if(peek == '(') {
  78. parentheseStack.push(parentheseState)
  79. isReg = 1
  80. isReturn = 0
  81. braceState = 1
  82. }
  83. else if(peek == ')') {
  84. isReg = parentheseStack.pop()
  85. isReturn = 0
  86. braceState = 0
  87. }
  88. else if(peek == '{') {
  89. if(isReturn) {
  90. braceState = 1
  91. }
  92. braceStack.push(braceState)
  93. isReturn = 0
  94. isReg = 1
  95. }
  96. else if(peek == '}') {
  97. braceState = braceStack.pop();
  98. isReg = !braceState
  99. isReturn = 0
  100. }
  101. else {
  102. var next = s.charAt(index)
  103. if(peek == ';') {
  104. braceState = 0
  105. }
  106. else if(peek == '-' && next == '-'
  107. || peek == '+' && next == '+'
  108. || peek == '=' && next == '>') {
  109. braceState = 0
  110. index++
  111. }
  112. else {
  113. braceState = 1
  114. }
  115. isReg = peek != ']'
  116. isReturn = 0
  117. }
  118. }
  119. return replace ? s : res
  120. function readch() {
  121. peek = s.charAt(index++)
  122. }
  123. function isBlank() {
  124. return /\s/.test(peek)
  125. }
  126. function isQuote() {
  127. return peek == '"' || peek == "'"
  128. }
  129. function dealQuote() {
  130. var start = index
  131. var c = peek
  132. var end = s.indexOf(c, start)
  133. if(end == -1) {
  134. index = length
  135. }
  136. else if(s.charAt(end - 1) != '\\') {
  137. index = end + 1
  138. }
  139. else {
  140. while(index < length) {
  141. readch()
  142. if(peek == '\\') {
  143. index++
  144. }
  145. else if(peek == c) {
  146. break
  147. }
  148. }
  149. }
  150. if(modName) {
  151. var d = {
  152. 'string': modName == 2
  153. ? s.slice(last, index)
  154. : s.slice(last, s.indexOf(')', index) + 1),
  155. 'path': s.slice(start, index - 1),
  156. 'index': last,
  157. 'flag': flag
  158. }
  159. res.push(d)
  160. if(replace) {
  161. var rep = replace(d)
  162. s = s.slice(0, last) + rep + s.slice(last + d.string.length)
  163. if(rep.length != d.string.length) {
  164. index = last + rep.length
  165. length = s.length
  166. }
  167. }
  168. modName = 0
  169. }
  170. }
  171. function dealReg() {
  172. index--
  173. while(index < length) {
  174. readch()
  175. if(peek == '\\') {
  176. index++
  177. }
  178. else if(peek == '/') {
  179. break
  180. }
  181. else if(peek == '[') {
  182. while(index < length) {
  183. readch()
  184. if(peek == '\\') {
  185. index++
  186. }
  187. else if(peek == ']') {
  188. break
  189. }
  190. }
  191. }
  192. }
  193. }
  194. function isWord() {
  195. return /[a-z_$]/i.test(peek)
  196. }
  197. function dealWord() {
  198. var s2 = s.slice(index - 1)
  199. var r = /^[\w$]+/.exec(s2)[0]
  200. parentheseState = {
  201. 'if': 1,
  202. 'for': 1,
  203. 'while': 1,
  204. 'with': 1
  205. }[r]
  206. isReg = {
  207. 'break': 1,
  208. 'case': 1,
  209. 'continue': 1,
  210. 'debugger': 1,
  211. 'delete': 1,
  212. 'do': 1,
  213. 'else': 1,
  214. 'false': 1,
  215. 'if': 1,
  216. 'in': 1,
  217. 'instanceof': 1,
  218. 'return': 1,
  219. 'typeof': 1,
  220. 'void': 1
  221. }[r]
  222. isReturn = r == 'return'
  223. braceState = {
  224. 'instanceof': 1,
  225. 'delete': 1,
  226. 'void': 1,
  227. 'typeof': 1,
  228. 'return': 1
  229. }.hasOwnProperty(r)
  230. if(r == 'require') {
  231. modName = includeAsync
  232. ? /^require\s*(?:\/\*[\s\S]*?\*\/\s*)?[.\w$]*\s*(?:\/\*[\s\S]*?\*\/\s*)?\(\s*(['"]).+?\1\s*[),]/.test(s2)
  233. : /^require\s*(?:\/\*[\s\S]*?\*\/\s*)?\(\s*(['"]).+?\1\s*[),]/.test(s2)
  234. }
  235. else if(r == 'import') {
  236. // ignore `{ import() {} }`
  237. modName = /^import[^(]*?['"]/.test(s2);
  238. if (modName) modName = 2;
  239. }
  240. if(modName) {
  241. last = index - 1
  242. if(r == 'require') {
  243. r = includeAsync
  244. ? /^require\s*(?:\/\*[\s\S]*?\*\/\s*)?[.\w$]*\s*(?:\/\*[\s\S]*?\*\/\s*)?\(\s*['"]/.exec(s2)[0]
  245. : /^require\s*(?:\/\*[\s\S]*?\*\/\s*)?\(\s*['"]/.exec(s2)[0]
  246. index += r.length - 2
  247. flag = /^require\s*(?:\/\*[\s\S]*?\*\/\s*)?([.\w$]+)/.test(s2)
  248. ? /^require\s*(?:\/\*[\s\S]*?\*\/\s*)?([.\w$]+)/.exec(s2)[1]
  249. : null
  250. }
  251. else if (r === 'import') {
  252. r = /^import[^(]*?['"]/.exec(s2)[0];
  253. index += r.length - 2
  254. quote = r.charAt(r.length - 1)
  255. }
  256. }
  257. else {
  258. index += /^[\w$]+(?:\s*\.\s*[\w$]+)*/.exec(s2)[0].length - 1
  259. }
  260. }
  261. function isNumber() {
  262. return /\d/.test(peek)
  263. || peek == '.' && /\d/.test(s.charAt(index))
  264. }
  265. function dealNumber() {
  266. var s2 = s.slice(index - 1)
  267. var r
  268. if(peek == '.') {
  269. r = /^\.\d+(?:E[+-]?\d*)?\s*/i.exec(s2)[0]
  270. }
  271. else if(/^0x[\da-f]*/i.test(s2)) {
  272. r = /^0x[\da-f]*\s*/i.exec(s2)[0]
  273. }
  274. else {
  275. r = /^\d+\.?\d*(?:E[+-]?\d*)?\s*/i.exec(s2)[0]
  276. }
  277. index += r.length - 1
  278. isReg = 0
  279. }
  280. }
  281. module.exports = parseDependencies