Skip to content

Instantly share code, notes, and snippets.

@coderek
Created July 12, 2015 22:01
Show Gist options
  • Save coderek/c65c150b67f7243baf7a to your computer and use it in GitHub Desktop.
Save coderek/c65c150b67f7243baf7a to your computer and use it in GitHub Desktop.
parse pbxproj file to JSON
fs = require('fs')
[
KEY,
VALUE,
OBJECT_START,
OBJECT_END,
ARRAY_START,
ARRAY_END,
ASSIGN
] = [0..100]
module.exports =
class XCProjectFileParser
file: null
constructor: (p)->
@f = fs.readFileSync p, encoding = "utf8"
parse: ->
cleanedArr = @removeWhiteSpaces(@stripComments())
tokens = @tokenize(cleanedArr)
stack = [{key: 'root'}]
for i, t of tokens
switch t.type
when OBJECT_START
stack.push '{}'
when OBJECT_END
# reduce
j = stack.length - 1
obj = {}
while stack[j] isnt '{}'
obj[stack[j].key] = stack[j].value
j = j - 1
stack[j - 1]['value'] = obj if j > 0
stack = stack.slice 0, j
when ARRAY_START
stack.push '[]'
when ARRAY_END
# reduce
j = stack.length - 1
arr = []
while stack[j] isnt '[]'
arr.push stack[j].value
j = j - 1
stack[j - 1]['value'] = arr if j > 0
stack = stack.slice 0, j
when KEY
stack.push {key: t.value, value: null}
when VALUE
len = stack.length
if len > 0 and stack[len - 1]['value'] == null
# k-v
stack[len - 1]['value'] = t.value
else
# array
stack.push {value: t.value, key: null}
return stack[0].value
tokenize: (stringArr) ->
pos = 0
string = ''
tokens = []
while pos < stringArr.length
ch = stringArr[pos]
if ch is '"'
c = pos + 1
pos = pos + 1
while stringArr[pos] isnt '"'
string = string + stringArr[pos]
pos = pos + 1
else
switch ch
when '{' then tokens.push {type: OBJECT_START, value: ch}
when '}' then tokens.push {type: OBJECT_END, value: ch}
when '(' then tokens.push {type: ARRAY_START, value: ch}
when ')' then tokens.push {type: ARRAY_END, value: ch}
when ','
tokens.push {type: VALUE, value: string}
string = ''
when ';'
tokens.push {type: VALUE, value: string}
string = ''
when '='
tokens.push {type: KEY, value: string}
tokens.push {type: ASSIGN, value: ch}
string = ''
else
string = string + ch
pos = pos + 1
if tokens[tokens.length - 1].value is ''
tokens.pop()
return tokens
removeWhiteSpaces: (chArr) ->
res = []
i = 0
while i < chArr.length
ch = chArr[i]
if ch is '"'
res.push chArr[i]
i = i + 1
while chArr[i] isnt '"'
res.push chArr[i]
i = i + 1
res.push chArr[i]
else
res.push ch unless /\s/.test ch
i = i + 1
return res
stripComments: ->
res = []
inComments = false
len = @f.length
pos = 0
while pos < len
if inComments
if @f[pos] is '/' and @f[pos - 1] is '*'
inComments = false
else
if @f[pos] is '/' and @f[pos + 1] is '*'
inComments = true
else if @f[pos] is '/' and @f[pos + 1] is '/'
pos = pos + 1 while @f[pos] isnt '\n'
else
res.push @f[pos]
pos = pos + 1
return res
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment