/**
|
* util-deps.js - The parser for dependencies
|
* ref: tests/research/parse-dependencies/test.html
|
* ref: https://github.com/seajs/crequire
|
*/
|
|
function parseDependencies(s, replace, includeAsync) {
|
if(replace === true) {
|
includeAsync = true;
|
replace = null;
|
}
|
if(s.indexOf('require') == -1 && s.indexOf('import') == -1) {
|
return replace ? s : [];
|
}
|
var index = 0, peek, length = s.length, isReg = 1, modName = 0, res = []
|
var parentheseState = 0, parentheseStack = []
|
var braceState, braceStack = [], isReturn
|
var last
|
var flag
|
var quote
|
while(index < length) {
|
readch()
|
if(isBlank()) {
|
if(isReturn && (peek == '\n' || peek == '\r')) {
|
braceState = 0
|
isReturn = 0
|
}
|
}
|
else if(isQuote()) {
|
dealQuote()
|
isReg = 1
|
isReturn = 0
|
braceState = 0
|
}
|
else if(peek == '/') {
|
readch()
|
if(peek == '/') {
|
index = s.indexOf('\n', index)
|
if(index == -1) {
|
index = s.length
|
}
|
}
|
else if(peek == '*') {
|
var i = s.indexOf('\n', index)
|
index = s.indexOf('*/', index)
|
if(index == -1) {
|
index = length
|
}
|
else {
|
index += 2
|
}
|
if(isReturn && i != -1 && i < index) {
|
braceState = 0
|
isReturn = 0
|
}
|
}
|
else if(isReg) {
|
dealReg()
|
isReg = 0
|
isReturn = 0
|
braceState = 0
|
}
|
else {
|
index--
|
isReg = 1
|
isReturn = 0
|
braceState = 1
|
}
|
}
|
else if(isWord()) {
|
dealWord()
|
}
|
else if(isNumber()) {
|
dealNumber()
|
isReturn = 0
|
braceState = 0
|
}
|
else if(peek == '(') {
|
parentheseStack.push(parentheseState)
|
isReg = 1
|
isReturn = 0
|
braceState = 1
|
}
|
else if(peek == ')') {
|
isReg = parentheseStack.pop()
|
isReturn = 0
|
braceState = 0
|
}
|
else if(peek == '{') {
|
if(isReturn) {
|
braceState = 1
|
}
|
braceStack.push(braceState)
|
isReturn = 0
|
isReg = 1
|
}
|
else if(peek == '}') {
|
braceState = braceStack.pop();
|
isReg = !braceState
|
isReturn = 0
|
}
|
else {
|
var next = s.charAt(index)
|
if(peek == ';') {
|
braceState = 0
|
}
|
else if(peek == '-' && next == '-'
|
|| peek == '+' && next == '+'
|
|| peek == '=' && next == '>') {
|
braceState = 0
|
index++
|
}
|
else {
|
braceState = 1
|
}
|
isReg = peek != ']'
|
isReturn = 0
|
}
|
}
|
return replace ? s : res
|
function readch() {
|
peek = s.charAt(index++)
|
}
|
function isBlank() {
|
return /\s/.test(peek)
|
}
|
function isQuote() {
|
return peek == '"' || peek == "'"
|
}
|
function dealQuote() {
|
var start = index
|
var c = peek
|
var end = s.indexOf(c, start)
|
if(end == -1) {
|
index = length
|
}
|
else if(s.charAt(end - 1) != '\\') {
|
index = end + 1
|
}
|
else {
|
while(index < length) {
|
readch()
|
if(peek == '\\') {
|
index++
|
}
|
else if(peek == c) {
|
break
|
}
|
}
|
}
|
if(modName) {
|
var d = {
|
'string': modName == 2
|
? s.slice(last, index)
|
: s.slice(last, s.indexOf(')', index) + 1),
|
'path': s.slice(start, index - 1),
|
'index': last,
|
'flag': flag
|
}
|
res.push(d)
|
if(replace) {
|
var rep = replace(d)
|
s = s.slice(0, last) + rep + s.slice(last + d.string.length)
|
if(rep.length != d.string.length) {
|
index = last + rep.length
|
length = s.length
|
}
|
}
|
modName = 0
|
}
|
}
|
function dealReg() {
|
index--
|
while(index < length) {
|
readch()
|
if(peek == '\\') {
|
index++
|
}
|
else if(peek == '/') {
|
break
|
}
|
else if(peek == '[') {
|
while(index < length) {
|
readch()
|
if(peek == '\\') {
|
index++
|
}
|
else if(peek == ']') {
|
break
|
}
|
}
|
}
|
}
|
}
|
function isWord() {
|
return /[a-z_$]/i.test(peek)
|
}
|
function dealWord() {
|
var s2 = s.slice(index - 1)
|
var r = /^[\w$]+/.exec(s2)[0]
|
parentheseState = {
|
'if': 1,
|
'for': 1,
|
'while': 1,
|
'with': 1
|
}[r]
|
isReg = {
|
'break': 1,
|
'case': 1,
|
'continue': 1,
|
'debugger': 1,
|
'delete': 1,
|
'do': 1,
|
'else': 1,
|
'false': 1,
|
'if': 1,
|
'in': 1,
|
'instanceof': 1,
|
'return': 1,
|
'typeof': 1,
|
'void': 1
|
}[r]
|
isReturn = r == 'return'
|
braceState = {
|
'instanceof': 1,
|
'delete': 1,
|
'void': 1,
|
'typeof': 1,
|
'return': 1
|
}.hasOwnProperty(r)
|
if(r == 'require') {
|
modName = includeAsync
|
? /^require\s*(?:\/\*[\s\S]*?\*\/\s*)?[.\w$]*\s*(?:\/\*[\s\S]*?\*\/\s*)?\(\s*(['"]).+?\1\s*[),]/.test(s2)
|
: /^require\s*(?:\/\*[\s\S]*?\*\/\s*)?\(\s*(['"]).+?\1\s*[),]/.test(s2)
|
}
|
else if(r == 'import') {
|
// ignore `{ import() {} }`
|
modName = /^import[^(]*?['"]/.test(s2);
|
if (modName) modName = 2;
|
}
|
if(modName) {
|
last = index - 1
|
if(r == 'require') {
|
r = includeAsync
|
? /^require\s*(?:\/\*[\s\S]*?\*\/\s*)?[.\w$]*\s*(?:\/\*[\s\S]*?\*\/\s*)?\(\s*['"]/.exec(s2)[0]
|
: /^require\s*(?:\/\*[\s\S]*?\*\/\s*)?\(\s*['"]/.exec(s2)[0]
|
index += r.length - 2
|
flag = /^require\s*(?:\/\*[\s\S]*?\*\/\s*)?([.\w$]+)/.test(s2)
|
? /^require\s*(?:\/\*[\s\S]*?\*\/\s*)?([.\w$]+)/.exec(s2)[1]
|
: null
|
}
|
else if (r === 'import') {
|
r = /^import[^(]*?['"]/.exec(s2)[0];
|
index += r.length - 2
|
quote = r.charAt(r.length - 1)
|
}
|
}
|
else {
|
index += /^[\w$]+(?:\s*\.\s*[\w$]+)*/.exec(s2)[0].length - 1
|
}
|
}
|
function isNumber() {
|
return /\d/.test(peek)
|
|| peek == '.' && /\d/.test(s.charAt(index))
|
}
|
function dealNumber() {
|
var s2 = s.slice(index - 1)
|
var r
|
if(peek == '.') {
|
r = /^\.\d+(?:E[+-]?\d*)?\s*/i.exec(s2)[0]
|
}
|
else if(/^0x[\da-f]*/i.test(s2)) {
|
r = /^0x[\da-f]*\s*/i.exec(s2)[0]
|
}
|
else {
|
r = /^\d+\.?\d*(?:E[+-]?\d*)?\s*/i.exec(s2)[0]
|
}
|
index += r.length - 1
|
isReg = 0
|
}
|
}
|
|
module.exports = parseDependencies
|