You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

284 lines
6.3 KiB

/**
* 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