exports.starts = (string, literal, start) ->
literal is string.substr start, literal.length
此檔案包含我們希望在詞法分析器、重寫器和節點之間共用的常見輔助函式。合併物件、壓平陣列、計算字元,這類事情。
窺視給定字串的開頭,看看它是否符合某個順序。
exports.starts = (string, literal, start) ->
literal is string.substr start, literal.length
窺視給定字串的結尾,看看它是否符合某個順序。
exports.ends = (string, literal, back) ->
len = literal.length
literal is string.substr string.length - len - (back or 0), len
重複字串 n
次。
exports.repeat = repeat = (str, n) ->
使用聰明的演算法,讓字串串接操作達到 O(log(n))。
res = ''
while n > 0
res += str if n & 1
n >>>= 1
str += str
res
從陣列中移除所有假值。
exports.compact = (array) ->
item for item in array when item
計算字串中字串出現的次數。
exports.count = (string, substr) ->
num = pos = 0
return 1/0 unless substr.length
num++ while pos = 1 + string.indexOf substr, pos
num
合併物件,傳回一個具有兩方屬性的新副本。每次呼叫 Base#compile
時都會使用,以允許選項雜湊中的屬性向下傳播到樹狀結構,而不會污染其他分支。
exports.merge = (options, overrides) ->
extend (extend {}, options), overrides
使用另一個物件的屬性來延伸來源物件(淺層複製)。
extend = exports.extend = (object, properties) ->
for key, val of properties
object[key] = val
object
傳回陣列的壓平版本。對於從節點中取得 children
清單很方便。
exports.flatten = flatten = (array) ->
flattened = []
for element in array
if '[object Array]' is Object::toString.call element
flattened = flattened.concat flatten element
else
flattened.push element
flattened
從物件中刪除金鑰,傳回值。當節點在選項雜湊中尋找特定方法時很有用。
exports.del = (obj, key) ->
val = obj[key]
delete obj[key]
val
典型的 Array::some
exports.some = Array::some ? (fn) ->
return true for e in this when fn e
false
透過將文件放入註解中來反轉 Literate CoffeeScript 程式碼的簡單函式,產生可以「正常」編譯的 CoffeeScript 程式碼字串。
exports.invertLiterate = (code) ->
maybe_code = true
lines = for line in code.split('\n')
if maybe_code and /^([ ]{4}|[ ]{0,3}\t)/.test line
line
else if maybe_code = /^\s*$/.test line
line
else
'# ' + line
lines.join '\n'
合併兩個 jison 風格的位置資料物件。如果未提供 last
,這只會傳回 first
。
buildLocationData = (first, last) ->
if not last
first
else
first_line: first.first_line
first_column: first.first_column
last_line: last.last_line
last_column: last.last_column
這會傳回一個函式,它將物件作為參數,如果該物件是 AST 節點,則會更新該物件的 locationData。物件會以任一種方式傳回。
exports.addLocationDataFn = (first, last) ->
(obj) ->
if ((typeof obj) is 'object') and (!!obj['updateLocationDataIfMissing'])
obj.updateLocationDataIfMissing buildLocationData(first, last)
return obj
將 jison 位置資料轉換為字串。obj
可以是符號或 locationData。
exports.locationDataToString = (obj) ->
if ("2" of obj) and ("first_line" of obj[2]) then locationData = obj[2]
else if "first_line" of obj then locationData = obj
if locationData
"#{locationData.first_line + 1}:#{locationData.first_column + 1}-" +
"#{locationData.last_line + 1}:#{locationData.last_column + 1}"
else
"No location data"
與 basename
相容的 .coffee.md
版本,它會傳回不含副檔名的檔案。
exports.baseFileName = (file, stripExt = no, useWinPathSep = no) ->
pathSep = if useWinPathSep then /\\|\// else /\//
parts = file.split(pathSep)
file = parts[parts.length - 1]
return file unless stripExt and file.indexOf('.') >= 0
parts = file.split('.')
parts.pop()
parts.pop() if parts[parts.length - 1] is 'coffee' and parts.length > 1
parts.join('.')
判斷檔案名稱是否代表 CoffeeScript 檔案。
exports.isCoffee = (file) -> /\.((lit)?coffee|coffee\.md)$/.test file
判斷檔案名稱是否代表 Literate CoffeeScript 檔案。
exports.isLiterate = (file) -> /\.(litcoffee|coffee\.md)$/.test file
從給定的位置擲出 SyntaxError。錯誤的 toString
會傳回遵循「標準」格式 <filename>:<line>:<col>: <message>
的錯誤訊息,加上含有錯誤的行以及顯示錯誤位置的標記。
exports.throwSyntaxError = (message, location) ->
error = new SyntaxError message
error.location = location
error.toString = syntaxErrorToString
不要顯示編譯器的堆疊追蹤,而是顯示我們的自訂錯誤訊息(這在例如編譯 CoffeeScript 的 Node.js 應用程式中錯誤浮現時很有用)。
error.stack = error.toString()
throw error
如果編譯器 SyntaxError 尚未包含原始碼資訊,則更新它。
exports.updateSyntaxError = (error, code, filename) ->
避免搞亂其他錯誤(例如可能的錯誤)的 stack
屬性。
if error.toString is syntaxErrorToString
error.code or= code
error.filename or= filename
error.stack = error.toString()
error
syntaxErrorToString = ->
return Error::toString.call @ unless @code and @location
{first_line, first_column, last_line, last_column} = @location
last_line ?= first_line
last_column ?= first_column
filename = @filename or '[stdin]'
codeLine = @code.split('\n')[first_line]
start = first_column
在多行錯誤中只顯示第一行。
end = if first_line is last_line then last_column + 1 else codeLine.length
marker = codeLine[...start].replace(/[^\s]/g, ' ') + repeat('^', end - start)
檢查我們是否在支援顏色的 TTY 上執行。
if process?
colorsEnabled = process.stdout?.isTTY and not process.env?.NODE_DISABLE_COLORS
if @colorful ? colorsEnabled
colorize = (str) -> "\x1B[1;31m#{str}\x1B[0m"
codeLine = codeLine[...start] + colorize(codeLine[start...end]) + codeLine[end..]
marker = colorize marker
"""
#{filename}:#{first_line + 1}:#{first_column + 1}: error: #{@message}
#{codeLine}
#{marker}
"""
exports.nameWhitespaceCharacter = (string) ->
switch string
when ' ' then 'space'
when '\n' then 'newline'
when '\r' then 'carriage return'
when '\t' then 'tab'
else string