Comparing version 0.12.6 to 0.12.7
1203
lib/lines.js
@@ -17,33 +17,55 @@ var assert = require("assert"); | ||
var useSymbol = typeof Symbol === "function"; | ||
var secretKey = "recastLinesSecret"; | ||
if (useSymbol) { | ||
secretKey = Symbol.for(secretKey); | ||
} | ||
function getSecret(lines) { | ||
return lines[secretKey]; | ||
return lines[secretKey]; | ||
} | ||
function Lines(infos, sourceFileName) { | ||
assert.ok(this instanceof Lines); | ||
assert.ok(infos.length > 0); | ||
assert.ok(this instanceof Lines); | ||
assert.ok(infos.length > 0); | ||
if (sourceFileName) { | ||
isString.assert(sourceFileName); | ||
} else { | ||
sourceFileName = null; | ||
} | ||
if (sourceFileName) { | ||
isString.assert(sourceFileName); | ||
} else { | ||
sourceFileName = null; | ||
} | ||
Object.defineProperty(this, secretKey, { | ||
value: { | ||
infos: infos, | ||
mappings: [], | ||
name: sourceFileName, | ||
cachedSourceMap: null | ||
} | ||
}); | ||
setSymbolOrKey(this, secretKey, { | ||
infos: infos, | ||
mappings: [], | ||
name: sourceFileName, | ||
cachedSourceMap: null | ||
}); | ||
if (sourceFileName) { | ||
getSecret(this).mappings.push(new Mapping(this, { | ||
start: this.firstPos(), | ||
end: this.lastPos() | ||
})); | ||
} | ||
this.length = infos.length; | ||
this.name = sourceFileName; | ||
if (sourceFileName) { | ||
getSecret(this).mappings.push(new Mapping(this, { | ||
start: this.firstPos(), | ||
end: this.lastPos() | ||
})); | ||
} | ||
} | ||
function setSymbolOrKey(obj, key, value) { | ||
if (useSymbol) { | ||
return obj[key] = value; | ||
} | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: false, | ||
writable: false, | ||
configurable: true | ||
}); | ||
return value; | ||
} | ||
// Exposed for instanceof checks. The fromString function should be used | ||
@@ -54,27 +76,10 @@ // to create new Lines objects. | ||
// These properties used to be assigned to each new object in the Lines | ||
// constructor, but we can more efficiently stuff them into the secret and | ||
// let these lazy accessors compute their values on-the-fly. | ||
Object.defineProperties(Lp, { | ||
length: { | ||
get: function() { | ||
return getSecret(this).infos.length; | ||
} | ||
}, | ||
name: { | ||
get: function() { | ||
return getSecret(this).name; | ||
} | ||
} | ||
}); | ||
function copyLineInfo(info) { | ||
return { | ||
line: info.line, | ||
indent: info.indent, | ||
locked: info.locked, | ||
sliceStart: info.sliceStart, | ||
sliceEnd: info.sliceEnd | ||
}; | ||
return { | ||
line: info.line, | ||
indent: info.indent, | ||
locked: info.locked, | ||
sliceStart: info.sliceStart, | ||
sliceEnd: info.sliceEnd | ||
}; | ||
} | ||
@@ -87,35 +92,35 @@ | ||
function countSpaces(spaces, tabWidth) { | ||
var count = 0; | ||
var len = spaces.length; | ||
var count = 0; | ||
var len = spaces.length; | ||
for (var i = 0; i < len; ++i) { | ||
switch (spaces.charCodeAt(i)) { | ||
case 9: // '\t' | ||
assert.strictEqual(typeof tabWidth, "number"); | ||
assert.ok(tabWidth > 0); | ||
for (var i = 0; i < len; ++i) { | ||
switch (spaces.charCodeAt(i)) { | ||
case 9: // '\t' | ||
assert.strictEqual(typeof tabWidth, "number"); | ||
assert.ok(tabWidth > 0); | ||
var next = Math.ceil(count / tabWidth) * tabWidth; | ||
if (next === count) { | ||
count += tabWidth; | ||
} else { | ||
count = next; | ||
} | ||
var next = Math.ceil(count / tabWidth) * tabWidth; | ||
if (next === count) { | ||
count += tabWidth; | ||
} else { | ||
count = next; | ||
} | ||
break; | ||
break; | ||
case 11: // '\v' | ||
case 12: // '\f' | ||
case 13: // '\r' | ||
case 0xfeff: // zero-width non-breaking space | ||
// These characters contribute nothing to indentation. | ||
break; | ||
case 11: // '\v' | ||
case 12: // '\f' | ||
case 13: // '\r' | ||
case 0xfeff: // zero-width non-breaking space | ||
// These characters contribute nothing to indentation. | ||
break; | ||
case 32: // ' ' | ||
default: // Treat all other whitespace like ' '. | ||
count += 1; | ||
break; | ||
} | ||
case 32: // ' ' | ||
default: // Treat all other whitespace like ' '. | ||
count += 1; | ||
break; | ||
} | ||
} | ||
return count; | ||
return count; | ||
} | ||
@@ -128,3 +133,3 @@ exports.countSpaces = countSpaces; | ||
var lineTerminatorSeqExp = | ||
/\u000D\u000A|\u000D(?!\u000A)|\u000A|\u2028|\u2029/; | ||
/\u000D\u000A|\u000D(?!\u000A)|\u000A|\u2028|\u2029/; | ||
@@ -135,33 +140,33 @@ /** | ||
function fromString(string, options) { | ||
if (string instanceof Lines) | ||
return string; | ||
if (string instanceof Lines) | ||
return string; | ||
string += ""; | ||
string += ""; | ||
var tabWidth = options && options.tabWidth; | ||
var tabless = string.indexOf("\t") < 0; | ||
var locked = !! (options && options.locked); | ||
var cacheable = !options && tabless && (string.length <= maxCacheKeyLen); | ||
var tabWidth = options && options.tabWidth; | ||
var tabless = string.indexOf("\t") < 0; | ||
var locked = !! (options && options.locked); | ||
var cacheable = !options && tabless && (string.length <= maxCacheKeyLen); | ||
assert.ok(tabWidth || tabless, "No tab width specified but encountered tabs in string\n" + string); | ||
assert.ok(tabWidth || tabless, "No tab width specified but encountered tabs in string\n" + string); | ||
if (cacheable && hasOwn.call(fromStringCache, string)) | ||
return fromStringCache[string]; | ||
if (cacheable && hasOwn.call(fromStringCache, string)) | ||
return fromStringCache[string]; | ||
var lines = new Lines(string.split(lineTerminatorSeqExp).map(function(line) { | ||
var spaces = leadingSpaceExp.exec(line)[0]; | ||
return { | ||
line: line, | ||
indent: countSpaces(spaces, tabWidth), | ||
// Boolean indicating whether this line can be reindented. | ||
locked: locked, | ||
sliceStart: spaces.length, | ||
sliceEnd: line.length | ||
}; | ||
}), normalizeOptions(options).sourceFileName); | ||
var lines = new Lines(string.split(lineTerminatorSeqExp).map(function(line) { | ||
var spaces = leadingSpaceExp.exec(line)[0]; | ||
return { | ||
line: line, | ||
indent: countSpaces(spaces, tabWidth), | ||
// Boolean indicating whether this line can be reindented. | ||
locked: locked, | ||
sliceStart: spaces.length, | ||
sliceEnd: line.length | ||
}; | ||
}), normalizeOptions(options).sourceFileName); | ||
if (cacheable) | ||
fromStringCache[string] = lines; | ||
if (cacheable) | ||
fromStringCache[string] = lines; | ||
return lines; | ||
return lines; | ||
} | ||
@@ -171,285 +176,285 @@ exports.fromString = fromString; | ||
function isOnlyWhitespace(string) { | ||
return !/\S/.test(string); | ||
return !/\S/.test(string); | ||
} | ||
Lp.toString = function(options) { | ||
return this.sliceString(this.firstPos(), this.lastPos(), options); | ||
return this.sliceString(this.firstPos(), this.lastPos(), options); | ||
}; | ||
Lp.getSourceMap = function(sourceMapName, sourceRoot) { | ||
if (!sourceMapName) { | ||
// Although we could make up a name or generate an anonymous | ||
// source map, instead we assume that any consumer who does not | ||
// provide a name does not actually want a source map. | ||
return null; | ||
} | ||
if (!sourceMapName) { | ||
// Although we could make up a name or generate an anonymous | ||
// source map, instead we assume that any consumer who does not | ||
// provide a name does not actually want a source map. | ||
return null; | ||
} | ||
var targetLines = this; | ||
var targetLines = this; | ||
function updateJSON(json) { | ||
json = json || {}; | ||
function updateJSON(json) { | ||
json = json || {}; | ||
isString.assert(sourceMapName); | ||
json.file = sourceMapName; | ||
isString.assert(sourceMapName); | ||
json.file = sourceMapName; | ||
if (sourceRoot) { | ||
isString.assert(sourceRoot); | ||
json.sourceRoot = sourceRoot; | ||
} | ||
return json; | ||
if (sourceRoot) { | ||
isString.assert(sourceRoot); | ||
json.sourceRoot = sourceRoot; | ||
} | ||
var secret = getSecret(targetLines); | ||
if (secret.cachedSourceMap) { | ||
// Since Lines objects are immutable, we can reuse any source map | ||
// that was previously generated. Nevertheless, we return a new | ||
// JSON object here to protect the cached source map from outside | ||
// modification. | ||
return updateJSON(secret.cachedSourceMap.toJSON()); | ||
} | ||
return json; | ||
} | ||
var smg = new sourceMap.SourceMapGenerator(updateJSON()); | ||
var sourcesToContents = {}; | ||
var secret = getSecret(targetLines); | ||
if (secret.cachedSourceMap) { | ||
// Since Lines objects are immutable, we can reuse any source map | ||
// that was previously generated. Nevertheless, we return a new | ||
// JSON object here to protect the cached source map from outside | ||
// modification. | ||
return updateJSON(secret.cachedSourceMap.toJSON()); | ||
} | ||
secret.mappings.forEach(function(mapping) { | ||
var sourceCursor = mapping.sourceLines.skipSpaces( | ||
mapping.sourceLoc.start | ||
) || mapping.sourceLines.lastPos(); | ||
var smg = new sourceMap.SourceMapGenerator(updateJSON()); | ||
var sourcesToContents = {}; | ||
var targetCursor = targetLines.skipSpaces( | ||
mapping.targetLoc.start | ||
) || targetLines.lastPos(); | ||
secret.mappings.forEach(function(mapping) { | ||
var sourceCursor = mapping.sourceLines.skipSpaces( | ||
mapping.sourceLoc.start | ||
) || mapping.sourceLines.lastPos(); | ||
while (comparePos(sourceCursor, mapping.sourceLoc.end) < 0 && | ||
comparePos(targetCursor, mapping.targetLoc.end) < 0) { | ||
var targetCursor = targetLines.skipSpaces( | ||
mapping.targetLoc.start | ||
) || targetLines.lastPos(); | ||
var sourceChar = mapping.sourceLines.charAt(sourceCursor); | ||
var targetChar = targetLines.charAt(targetCursor); | ||
assert.strictEqual(sourceChar, targetChar); | ||
while (comparePos(sourceCursor, mapping.sourceLoc.end) < 0 && | ||
comparePos(targetCursor, mapping.targetLoc.end) < 0) { | ||
var sourceName = mapping.sourceLines.name; | ||
var sourceChar = mapping.sourceLines.charAt(sourceCursor); | ||
var targetChar = targetLines.charAt(targetCursor); | ||
assert.strictEqual(sourceChar, targetChar); | ||
// Add mappings one character at a time for maximum resolution. | ||
smg.addMapping({ | ||
source: sourceName, | ||
original: { line: sourceCursor.line, | ||
column: sourceCursor.column }, | ||
generated: { line: targetCursor.line, | ||
column: targetCursor.column } | ||
}); | ||
var sourceName = mapping.sourceLines.name; | ||
if (!hasOwn.call(sourcesToContents, sourceName)) { | ||
var sourceContent = mapping.sourceLines.toString(); | ||
smg.setSourceContent(sourceName, sourceContent); | ||
sourcesToContents[sourceName] = sourceContent; | ||
} | ||
// Add mappings one character at a time for maximum resolution. | ||
smg.addMapping({ | ||
source: sourceName, | ||
original: { line: sourceCursor.line, | ||
column: sourceCursor.column }, | ||
generated: { line: targetCursor.line, | ||
column: targetCursor.column } | ||
}); | ||
targetLines.nextPos(targetCursor, true); | ||
mapping.sourceLines.nextPos(sourceCursor, true); | ||
} | ||
}); | ||
if (!hasOwn.call(sourcesToContents, sourceName)) { | ||
var sourceContent = mapping.sourceLines.toString(); | ||
smg.setSourceContent(sourceName, sourceContent); | ||
sourcesToContents[sourceName] = sourceContent; | ||
} | ||
secret.cachedSourceMap = smg; | ||
targetLines.nextPos(targetCursor, true); | ||
mapping.sourceLines.nextPos(sourceCursor, true); | ||
} | ||
}); | ||
return smg.toJSON(); | ||
secret.cachedSourceMap = smg; | ||
return smg.toJSON(); | ||
}; | ||
Lp.bootstrapCharAt = function(pos) { | ||
assert.strictEqual(typeof pos, "object"); | ||
assert.strictEqual(typeof pos.line, "number"); | ||
assert.strictEqual(typeof pos.column, "number"); | ||
assert.strictEqual(typeof pos, "object"); | ||
assert.strictEqual(typeof pos.line, "number"); | ||
assert.strictEqual(typeof pos.column, "number"); | ||
var line = pos.line, | ||
column = pos.column, | ||
strings = this.toString().split(lineTerminatorSeqExp), | ||
string = strings[line - 1]; | ||
var line = pos.line, | ||
column = pos.column, | ||
strings = this.toString().split(lineTerminatorSeqExp), | ||
string = strings[line - 1]; | ||
if (typeof string === "undefined") | ||
return ""; | ||
if (typeof string === "undefined") | ||
return ""; | ||
if (column === string.length && | ||
line < strings.length) | ||
return "\n"; | ||
if (column === string.length && | ||
line < strings.length) | ||
return "\n"; | ||
if (column >= string.length) | ||
return ""; | ||
if (column >= string.length) | ||
return ""; | ||
return string.charAt(column); | ||
return string.charAt(column); | ||
}; | ||
Lp.charAt = function(pos) { | ||
assert.strictEqual(typeof pos, "object"); | ||
assert.strictEqual(typeof pos.line, "number"); | ||
assert.strictEqual(typeof pos.column, "number"); | ||
assert.strictEqual(typeof pos, "object"); | ||
assert.strictEqual(typeof pos.line, "number"); | ||
assert.strictEqual(typeof pos.column, "number"); | ||
var line = pos.line, | ||
column = pos.column, | ||
secret = getSecret(this), | ||
infos = secret.infos, | ||
info = infos[line - 1], | ||
c = column; | ||
var line = pos.line, | ||
column = pos.column, | ||
secret = getSecret(this), | ||
infos = secret.infos, | ||
info = infos[line - 1], | ||
c = column; | ||
if (typeof info === "undefined" || c < 0) | ||
return ""; | ||
if (typeof info === "undefined" || c < 0) | ||
return ""; | ||
var indent = this.getIndentAt(line); | ||
if (c < indent) | ||
return " "; | ||
var indent = this.getIndentAt(line); | ||
if (c < indent) | ||
return " "; | ||
c += info.sliceStart - indent; | ||
c += info.sliceStart - indent; | ||
if (c === info.sliceEnd && | ||
line < this.length) | ||
return "\n"; | ||
if (c === info.sliceEnd && | ||
line < this.length) | ||
return "\n"; | ||
if (c >= info.sliceEnd) | ||
return ""; | ||
if (c >= info.sliceEnd) | ||
return ""; | ||
return info.line.charAt(c); | ||
return info.line.charAt(c); | ||
}; | ||
Lp.stripMargin = function(width, skipFirstLine) { | ||
if (width === 0) | ||
return this; | ||
if (width === 0) | ||
return this; | ||
assert.ok(width > 0, "negative margin: " + width); | ||
assert.ok(width > 0, "negative margin: " + width); | ||
if (skipFirstLine && this.length === 1) | ||
return this; | ||
if (skipFirstLine && this.length === 1) | ||
return this; | ||
var secret = getSecret(this); | ||
var secret = getSecret(this); | ||
var lines = new Lines(secret.infos.map(function(info, i) { | ||
if (info.line && (i > 0 || !skipFirstLine)) { | ||
info = copyLineInfo(info); | ||
info.indent = Math.max(0, info.indent - width); | ||
} | ||
return info; | ||
})); | ||
if (secret.mappings.length > 0) { | ||
var newMappings = getSecret(lines).mappings; | ||
assert.strictEqual(newMappings.length, 0); | ||
secret.mappings.forEach(function(mapping) { | ||
newMappings.push(mapping.indent(width, skipFirstLine, true)); | ||
}); | ||
var lines = new Lines(secret.infos.map(function(info, i) { | ||
if (info.line && (i > 0 || !skipFirstLine)) { | ||
info = copyLineInfo(info); | ||
info.indent = Math.max(0, info.indent - width); | ||
} | ||
return info; | ||
})); | ||
return lines; | ||
if (secret.mappings.length > 0) { | ||
var newMappings = getSecret(lines).mappings; | ||
assert.strictEqual(newMappings.length, 0); | ||
secret.mappings.forEach(function(mapping) { | ||
newMappings.push(mapping.indent(width, skipFirstLine, true)); | ||
}); | ||
} | ||
return lines; | ||
}; | ||
Lp.indent = function(by) { | ||
if (by === 0) | ||
return this; | ||
if (by === 0) | ||
return this; | ||
var secret = getSecret(this); | ||
var secret = getSecret(this); | ||
var lines = new Lines(secret.infos.map(function(info) { | ||
if (info.line && ! info.locked) { | ||
info = copyLineInfo(info); | ||
info.indent += by; | ||
} | ||
return info | ||
})); | ||
if (secret.mappings.length > 0) { | ||
var newMappings = getSecret(lines).mappings; | ||
assert.strictEqual(newMappings.length, 0); | ||
secret.mappings.forEach(function(mapping) { | ||
newMappings.push(mapping.indent(by)); | ||
}); | ||
var lines = new Lines(secret.infos.map(function(info) { | ||
if (info.line && ! info.locked) { | ||
info = copyLineInfo(info); | ||
info.indent += by; | ||
} | ||
return info | ||
})); | ||
return lines; | ||
if (secret.mappings.length > 0) { | ||
var newMappings = getSecret(lines).mappings; | ||
assert.strictEqual(newMappings.length, 0); | ||
secret.mappings.forEach(function(mapping) { | ||
newMappings.push(mapping.indent(by)); | ||
}); | ||
} | ||
return lines; | ||
}; | ||
Lp.indentTail = function(by) { | ||
if (by === 0) | ||
return this; | ||
if (by === 0) | ||
return this; | ||
if (this.length < 2) | ||
return this; | ||
if (this.length < 2) | ||
return this; | ||
var secret = getSecret(this); | ||
var secret = getSecret(this); | ||
var lines = new Lines(secret.infos.map(function(info, i) { | ||
if (i > 0 && info.line && ! info.locked) { | ||
info = copyLineInfo(info); | ||
info.indent += by; | ||
} | ||
var lines = new Lines(secret.infos.map(function(info, i) { | ||
if (i > 0 && info.line && ! info.locked) { | ||
info = copyLineInfo(info); | ||
info.indent += by; | ||
} | ||
return info; | ||
})); | ||
return info; | ||
})); | ||
if (secret.mappings.length > 0) { | ||
var newMappings = getSecret(lines).mappings; | ||
assert.strictEqual(newMappings.length, 0); | ||
secret.mappings.forEach(function(mapping) { | ||
newMappings.push(mapping.indent(by, true)); | ||
}); | ||
} | ||
if (secret.mappings.length > 0) { | ||
var newMappings = getSecret(lines).mappings; | ||
assert.strictEqual(newMappings.length, 0); | ||
secret.mappings.forEach(function(mapping) { | ||
newMappings.push(mapping.indent(by, true)); | ||
}); | ||
} | ||
return lines; | ||
return lines; | ||
}; | ||
Lp.lockIndentTail = function () { | ||
if (this.length < 2) { | ||
return this; | ||
} | ||
if (this.length < 2) { | ||
return this; | ||
} | ||
var infos = getSecret(this).infos; | ||
var infos = getSecret(this).infos; | ||
return new Lines(infos.map(function (info, i) { | ||
info = copyLineInfo(info); | ||
info.locked = i > 0; | ||
return info; | ||
})); | ||
return new Lines(infos.map(function (info, i) { | ||
info = copyLineInfo(info); | ||
info.locked = i > 0; | ||
return info; | ||
})); | ||
}; | ||
Lp.getIndentAt = function(line) { | ||
assert.ok(line >= 1, "no line " + line + " (line numbers start from 1)"); | ||
var secret = getSecret(this), | ||
info = secret.infos[line - 1]; | ||
return Math.max(info.indent, 0); | ||
assert.ok(line >= 1, "no line " + line + " (line numbers start from 1)"); | ||
var secret = getSecret(this), | ||
info = secret.infos[line - 1]; | ||
return Math.max(info.indent, 0); | ||
}; | ||
Lp.guessTabWidth = function() { | ||
var secret = getSecret(this); | ||
if (hasOwn.call(secret, "cachedTabWidth")) { | ||
return secret.cachedTabWidth; | ||
} | ||
var secret = getSecret(this); | ||
if (hasOwn.call(secret, "cachedTabWidth")) { | ||
return secret.cachedTabWidth; | ||
} | ||
var counts = []; // Sparse array. | ||
var lastIndent = 0; | ||
var counts = []; // Sparse array. | ||
var lastIndent = 0; | ||
for (var line = 1, last = this.length; line <= last; ++line) { | ||
var info = secret.infos[line - 1]; | ||
var sliced = info.line.slice(info.sliceStart, info.sliceEnd); | ||
for (var line = 1, last = this.length; line <= last; ++line) { | ||
var info = secret.infos[line - 1]; | ||
var sliced = info.line.slice(info.sliceStart, info.sliceEnd); | ||
// Whitespace-only lines don't tell us much about the likely tab | ||
// width of this code. | ||
if (isOnlyWhitespace(sliced)) { | ||
continue; | ||
} | ||
var diff = Math.abs(info.indent - lastIndent); | ||
counts[diff] = ~~counts[diff] + 1; | ||
lastIndent = info.indent; | ||
// Whitespace-only lines don't tell us much about the likely tab | ||
// width of this code. | ||
if (isOnlyWhitespace(sliced)) { | ||
continue; | ||
} | ||
var maxCount = -1; | ||
var result = 2; | ||
var diff = Math.abs(info.indent - lastIndent); | ||
counts[diff] = ~~counts[diff] + 1; | ||
lastIndent = info.indent; | ||
} | ||
for (var tabWidth = 1; | ||
tabWidth < counts.length; | ||
tabWidth += 1) { | ||
if (hasOwn.call(counts, tabWidth) && | ||
counts[tabWidth] > maxCount) { | ||
maxCount = counts[tabWidth]; | ||
result = tabWidth; | ||
} | ||
var maxCount = -1; | ||
var result = 2; | ||
for (var tabWidth = 1; | ||
tabWidth < counts.length; | ||
tabWidth += 1) { | ||
if (hasOwn.call(counts, tabWidth) && | ||
counts[tabWidth] > maxCount) { | ||
maxCount = counts[tabWidth]; | ||
result = tabWidth; | ||
} | ||
} | ||
return secret.cachedTabWidth = result; | ||
return secret.cachedTabWidth = result; | ||
}; | ||
@@ -461,438 +466,438 @@ | ||
Lp.startsWithComment = function () { | ||
var secret = getSecret(this); | ||
if (secret.infos.length === 0) { | ||
return false; | ||
} | ||
var firstLineInfo = secret.infos[0], | ||
sliceStart = firstLineInfo.sliceStart, | ||
sliceEnd = firstLineInfo.sliceEnd, | ||
firstLine = firstLineInfo.line.slice(sliceStart, sliceEnd).trim(); | ||
return firstLine.length === 0 || | ||
firstLine.slice(0, 2) === "//" || | ||
firstLine.slice(0, 2) === "/*"; | ||
var secret = getSecret(this); | ||
if (secret.infos.length === 0) { | ||
return false; | ||
} | ||
var firstLineInfo = secret.infos[0], | ||
sliceStart = firstLineInfo.sliceStart, | ||
sliceEnd = firstLineInfo.sliceEnd, | ||
firstLine = firstLineInfo.line.slice(sliceStart, sliceEnd).trim(); | ||
return firstLine.length === 0 || | ||
firstLine.slice(0, 2) === "//" || | ||
firstLine.slice(0, 2) === "/*"; | ||
}; | ||
Lp.isOnlyWhitespace = function() { | ||
return isOnlyWhitespace(this.toString()); | ||
return isOnlyWhitespace(this.toString()); | ||
}; | ||
Lp.isPrecededOnlyByWhitespace = function(pos) { | ||
var secret = getSecret(this); | ||
var info = secret.infos[pos.line - 1]; | ||
var indent = Math.max(info.indent, 0); | ||
var secret = getSecret(this); | ||
var info = secret.infos[pos.line - 1]; | ||
var indent = Math.max(info.indent, 0); | ||
var diff = pos.column - indent; | ||
if (diff <= 0) { | ||
// If pos.column does not exceed the indentation amount, then | ||
// there must be only whitespace before it. | ||
return true; | ||
} | ||
var diff = pos.column - indent; | ||
if (diff <= 0) { | ||
// If pos.column does not exceed the indentation amount, then | ||
// there must be only whitespace before it. | ||
return true; | ||
} | ||
var start = info.sliceStart; | ||
var end = Math.min(start + diff, info.sliceEnd); | ||
var prefix = info.line.slice(start, end); | ||
var start = info.sliceStart; | ||
var end = Math.min(start + diff, info.sliceEnd); | ||
var prefix = info.line.slice(start, end); | ||
return isOnlyWhitespace(prefix); | ||
return isOnlyWhitespace(prefix); | ||
}; | ||
Lp.getLineLength = function(line) { | ||
var secret = getSecret(this), | ||
info = secret.infos[line - 1]; | ||
return this.getIndentAt(line) + info.sliceEnd - info.sliceStart; | ||
var secret = getSecret(this), | ||
info = secret.infos[line - 1]; | ||
return this.getIndentAt(line) + info.sliceEnd - info.sliceStart; | ||
}; | ||
Lp.nextPos = function(pos, skipSpaces) { | ||
var l = Math.max(pos.line, 0), | ||
c = Math.max(pos.column, 0); | ||
var l = Math.max(pos.line, 0), | ||
c = Math.max(pos.column, 0); | ||
if (c < this.getLineLength(l)) { | ||
pos.column += 1; | ||
if (c < this.getLineLength(l)) { | ||
pos.column += 1; | ||
return skipSpaces | ||
? !!this.skipSpaces(pos, false, true) | ||
: true; | ||
} | ||
return skipSpaces | ||
? !!this.skipSpaces(pos, false, true) | ||
: true; | ||
} | ||
if (l < this.length) { | ||
pos.line += 1; | ||
pos.column = 0; | ||
if (l < this.length) { | ||
pos.line += 1; | ||
pos.column = 0; | ||
return skipSpaces | ||
? !!this.skipSpaces(pos, false, true) | ||
: true; | ||
} | ||
return skipSpaces | ||
? !!this.skipSpaces(pos, false, true) | ||
: true; | ||
} | ||
return false; | ||
return false; | ||
}; | ||
Lp.prevPos = function(pos, skipSpaces) { | ||
var l = pos.line, | ||
c = pos.column; | ||
var l = pos.line, | ||
c = pos.column; | ||
if (c < 1) { | ||
l -= 1; | ||
if (c < 1) { | ||
l -= 1; | ||
if (l < 1) | ||
return false; | ||
if (l < 1) | ||
return false; | ||
c = this.getLineLength(l); | ||
c = this.getLineLength(l); | ||
} else { | ||
c = Math.min(c - 1, this.getLineLength(l)); | ||
} | ||
} else { | ||
c = Math.min(c - 1, this.getLineLength(l)); | ||
} | ||
pos.line = l; | ||
pos.column = c; | ||
pos.line = l; | ||
pos.column = c; | ||
return skipSpaces | ||
? !!this.skipSpaces(pos, true, true) | ||
: true; | ||
return skipSpaces | ||
? !!this.skipSpaces(pos, true, true) | ||
: true; | ||
}; | ||
Lp.firstPos = function() { | ||
// Trivial, but provided for completeness. | ||
return { line: 1, column: 0 }; | ||
// Trivial, but provided for completeness. | ||
return { line: 1, column: 0 }; | ||
}; | ||
Lp.lastPos = function() { | ||
return { | ||
line: this.length, | ||
column: this.getLineLength(this.length) | ||
}; | ||
return { | ||
line: this.length, | ||
column: this.getLineLength(this.length) | ||
}; | ||
}; | ||
Lp.skipSpaces = function(pos, backward, modifyInPlace) { | ||
if (pos) { | ||
pos = modifyInPlace ? pos : { | ||
line: pos.line, | ||
column: pos.column | ||
}; | ||
} else if (backward) { | ||
pos = this.lastPos(); | ||
} else { | ||
pos = this.firstPos(); | ||
if (pos) { | ||
pos = modifyInPlace ? pos : { | ||
line: pos.line, | ||
column: pos.column | ||
}; | ||
} else if (backward) { | ||
pos = this.lastPos(); | ||
} else { | ||
pos = this.firstPos(); | ||
} | ||
if (backward) { | ||
while (this.prevPos(pos)) { | ||
if (!isOnlyWhitespace(this.charAt(pos)) && | ||
this.nextPos(pos)) { | ||
return pos; | ||
} | ||
} | ||
if (backward) { | ||
while (this.prevPos(pos)) { | ||
if (!isOnlyWhitespace(this.charAt(pos)) && | ||
this.nextPos(pos)) { | ||
return pos; | ||
} | ||
} | ||
return null; | ||
} else { | ||
while (isOnlyWhitespace(this.charAt(pos))) { | ||
if (!this.nextPos(pos)) { | ||
return null; | ||
} | ||
} | ||
} else { | ||
while (isOnlyWhitespace(this.charAt(pos))) { | ||
if (!this.nextPos(pos)) { | ||
return null; | ||
} | ||
} | ||
return pos; | ||
} | ||
return pos; | ||
} | ||
}; | ||
Lp.trimLeft = function() { | ||
var pos = this.skipSpaces(this.firstPos(), false, true); | ||
return pos ? this.slice(pos) : emptyLines; | ||
var pos = this.skipSpaces(this.firstPos(), false, true); | ||
return pos ? this.slice(pos) : emptyLines; | ||
}; | ||
Lp.trimRight = function() { | ||
var pos = this.skipSpaces(this.lastPos(), true, true); | ||
return pos ? this.slice(this.firstPos(), pos) : emptyLines; | ||
var pos = this.skipSpaces(this.lastPos(), true, true); | ||
return pos ? this.slice(this.firstPos(), pos) : emptyLines; | ||
}; | ||
Lp.trim = function() { | ||
var start = this.skipSpaces(this.firstPos(), false, true); | ||
if (start === null) | ||
return emptyLines; | ||
var start = this.skipSpaces(this.firstPos(), false, true); | ||
if (start === null) | ||
return emptyLines; | ||
var end = this.skipSpaces(this.lastPos(), true, true); | ||
assert.notStrictEqual(end, null); | ||
var end = this.skipSpaces(this.lastPos(), true, true); | ||
assert.notStrictEqual(end, null); | ||
return this.slice(start, end); | ||
return this.slice(start, end); | ||
}; | ||
Lp.eachPos = function(callback, startPos, skipSpaces) { | ||
var pos = this.firstPos(); | ||
var pos = this.firstPos(); | ||
if (startPos) { | ||
pos.line = startPos.line, | ||
pos.column = startPos.column | ||
} | ||
if (startPos) { | ||
pos.line = startPos.line, | ||
pos.column = startPos.column | ||
} | ||
if (skipSpaces && !this.skipSpaces(pos, false, true)) { | ||
return; // Encountered nothing but spaces. | ||
} | ||
if (skipSpaces && !this.skipSpaces(pos, false, true)) { | ||
return; // Encountered nothing but spaces. | ||
} | ||
do callback.call(this, pos); | ||
while (this.nextPos(pos, skipSpaces)); | ||
do callback.call(this, pos); | ||
while (this.nextPos(pos, skipSpaces)); | ||
}; | ||
Lp.bootstrapSlice = function(start, end) { | ||
var strings = this.toString().split( | ||
lineTerminatorSeqExp | ||
).slice( | ||
start.line - 1, | ||
end.line | ||
); | ||
var strings = this.toString().split( | ||
lineTerminatorSeqExp | ||
).slice( | ||
start.line - 1, | ||
end.line | ||
); | ||
strings.push(strings.pop().slice(0, end.column)); | ||
strings[0] = strings[0].slice(start.column); | ||
strings.push(strings.pop().slice(0, end.column)); | ||
strings[0] = strings[0].slice(start.column); | ||
return fromString(strings.join("\n")); | ||
return fromString(strings.join("\n")); | ||
}; | ||
Lp.slice = function(start, end) { | ||
if (!end) { | ||
if (!start) { | ||
// The client seems to want a copy of this Lines object, but | ||
// Lines objects are immutable, so it's perfectly adequate to | ||
// return the same object. | ||
return this; | ||
} | ||
// Slice to the end if no end position was provided. | ||
end = this.lastPos(); | ||
if (!end) { | ||
if (!start) { | ||
// The client seems to want a copy of this Lines object, but | ||
// Lines objects are immutable, so it's perfectly adequate to | ||
// return the same object. | ||
return this; | ||
} | ||
var secret = getSecret(this); | ||
var sliced = secret.infos.slice(start.line - 1, end.line); | ||
// Slice to the end if no end position was provided. | ||
end = this.lastPos(); | ||
} | ||
if (start.line === end.line) { | ||
sliced[0] = sliceInfo(sliced[0], start.column, end.column); | ||
} else { | ||
assert.ok(start.line < end.line); | ||
sliced[0] = sliceInfo(sliced[0], start.column); | ||
sliced.push(sliceInfo(sliced.pop(), 0, end.column)); | ||
} | ||
var secret = getSecret(this); | ||
var sliced = secret.infos.slice(start.line - 1, end.line); | ||
var lines = new Lines(sliced); | ||
if (start.line === end.line) { | ||
sliced[0] = sliceInfo(sliced[0], start.column, end.column); | ||
} else { | ||
assert.ok(start.line < end.line); | ||
sliced[0] = sliceInfo(sliced[0], start.column); | ||
sliced.push(sliceInfo(sliced.pop(), 0, end.column)); | ||
} | ||
if (secret.mappings.length > 0) { | ||
var newMappings = getSecret(lines).mappings; | ||
assert.strictEqual(newMappings.length, 0); | ||
secret.mappings.forEach(function(mapping) { | ||
var sliced = mapping.slice(this, start, end); | ||
if (sliced) { | ||
newMappings.push(sliced); | ||
} | ||
}, this); | ||
} | ||
var lines = new Lines(sliced); | ||
return lines; | ||
if (secret.mappings.length > 0) { | ||
var newMappings = getSecret(lines).mappings; | ||
assert.strictEqual(newMappings.length, 0); | ||
secret.mappings.forEach(function(mapping) { | ||
var sliced = mapping.slice(this, start, end); | ||
if (sliced) { | ||
newMappings.push(sliced); | ||
} | ||
}, this); | ||
} | ||
return lines; | ||
}; | ||
function sliceInfo(info, startCol, endCol) { | ||
var sliceStart = info.sliceStart; | ||
var sliceEnd = info.sliceEnd; | ||
var indent = Math.max(info.indent, 0); | ||
var lineLength = indent + sliceEnd - sliceStart; | ||
var sliceStart = info.sliceStart; | ||
var sliceEnd = info.sliceEnd; | ||
var indent = Math.max(info.indent, 0); | ||
var lineLength = indent + sliceEnd - sliceStart; | ||
if (typeof endCol === "undefined") { | ||
endCol = lineLength; | ||
} | ||
if (typeof endCol === "undefined") { | ||
endCol = lineLength; | ||
} | ||
startCol = Math.max(startCol, 0); | ||
endCol = Math.min(endCol, lineLength); | ||
endCol = Math.max(endCol, startCol); | ||
startCol = Math.max(startCol, 0); | ||
endCol = Math.min(endCol, lineLength); | ||
endCol = Math.max(endCol, startCol); | ||
if (endCol < indent) { | ||
indent = endCol; | ||
sliceEnd = sliceStart; | ||
} else { | ||
sliceEnd -= lineLength - endCol; | ||
} | ||
if (endCol < indent) { | ||
indent = endCol; | ||
sliceEnd = sliceStart; | ||
} else { | ||
sliceEnd -= lineLength - endCol; | ||
} | ||
lineLength = endCol; | ||
lineLength -= startCol; | ||
lineLength = endCol; | ||
lineLength -= startCol; | ||
if (startCol < indent) { | ||
indent -= startCol; | ||
} else { | ||
startCol -= indent; | ||
indent = 0; | ||
sliceStart += startCol; | ||
} | ||
if (startCol < indent) { | ||
indent -= startCol; | ||
} else { | ||
startCol -= indent; | ||
indent = 0; | ||
sliceStart += startCol; | ||
} | ||
assert.ok(indent >= 0); | ||
assert.ok(sliceStart <= sliceEnd); | ||
assert.strictEqual(lineLength, indent + sliceEnd - sliceStart); | ||
assert.ok(indent >= 0); | ||
assert.ok(sliceStart <= sliceEnd); | ||
assert.strictEqual(lineLength, indent + sliceEnd - sliceStart); | ||
if (info.indent === indent && | ||
info.sliceStart === sliceStart && | ||
info.sliceEnd === sliceEnd) { | ||
return info; | ||
} | ||
if (info.indent === indent && | ||
info.sliceStart === sliceStart && | ||
info.sliceEnd === sliceEnd) { | ||
return info; | ||
} | ||
return { | ||
line: info.line, | ||
indent: indent, | ||
// A destructive slice always unlocks indentation. | ||
locked: false, | ||
sliceStart: sliceStart, | ||
sliceEnd: sliceEnd | ||
}; | ||
return { | ||
line: info.line, | ||
indent: indent, | ||
// A destructive slice always unlocks indentation. | ||
locked: false, | ||
sliceStart: sliceStart, | ||
sliceEnd: sliceEnd | ||
}; | ||
} | ||
Lp.bootstrapSliceString = function(start, end, options) { | ||
return this.slice(start, end).toString(options); | ||
return this.slice(start, end).toString(options); | ||
}; | ||
Lp.sliceString = function(start, end, options) { | ||
if (!end) { | ||
if (!start) { | ||
// The client seems to want a copy of this Lines object, but | ||
// Lines objects are immutable, so it's perfectly adequate to | ||
// return the same object. | ||
return this; | ||
} | ||
// Slice to the end if no end position was provided. | ||
end = this.lastPos(); | ||
if (!end) { | ||
if (!start) { | ||
// The client seems to want a copy of this Lines object, but | ||
// Lines objects are immutable, so it's perfectly adequate to | ||
// return the same object. | ||
return this; | ||
} | ||
options = normalizeOptions(options); | ||
// Slice to the end if no end position was provided. | ||
end = this.lastPos(); | ||
} | ||
var infos = getSecret(this).infos; | ||
var parts = []; | ||
var tabWidth = options.tabWidth; | ||
options = normalizeOptions(options); | ||
for (var line = start.line; line <= end.line; ++line) { | ||
var info = infos[line - 1]; | ||
var infos = getSecret(this).infos; | ||
var parts = []; | ||
var tabWidth = options.tabWidth; | ||
if (line === start.line) { | ||
if (line === end.line) { | ||
info = sliceInfo(info, start.column, end.column); | ||
} else { | ||
info = sliceInfo(info, start.column); | ||
} | ||
} else if (line === end.line) { | ||
info = sliceInfo(info, 0, end.column); | ||
} | ||
for (var line = start.line; line <= end.line; ++line) { | ||
var info = infos[line - 1]; | ||
var indent = Math.max(info.indent, 0); | ||
if (line === start.line) { | ||
if (line === end.line) { | ||
info = sliceInfo(info, start.column, end.column); | ||
} else { | ||
info = sliceInfo(info, start.column); | ||
} | ||
} else if (line === end.line) { | ||
info = sliceInfo(info, 0, end.column); | ||
} | ||
var before = info.line.slice(0, info.sliceStart); | ||
if (options.reuseWhitespace && | ||
isOnlyWhitespace(before) && | ||
countSpaces(before, options.tabWidth) === indent) { | ||
// Reuse original spaces if the indentation is correct. | ||
parts.push(info.line.slice(0, info.sliceEnd)); | ||
continue; | ||
} | ||
var indent = Math.max(info.indent, 0); | ||
var tabs = 0; | ||
var spaces = indent; | ||
var before = info.line.slice(0, info.sliceStart); | ||
if (options.reuseWhitespace && | ||
isOnlyWhitespace(before) && | ||
countSpaces(before, options.tabWidth) === indent) { | ||
// Reuse original spaces if the indentation is correct. | ||
parts.push(info.line.slice(0, info.sliceEnd)); | ||
continue; | ||
} | ||
if (options.useTabs) { | ||
tabs = Math.floor(indent / tabWidth); | ||
spaces -= tabs * tabWidth; | ||
} | ||
var tabs = 0; | ||
var spaces = indent; | ||
var result = ""; | ||
if (options.useTabs) { | ||
tabs = Math.floor(indent / tabWidth); | ||
spaces -= tabs * tabWidth; | ||
} | ||
if (tabs > 0) { | ||
result += new Array(tabs + 1).join("\t"); | ||
} | ||
var result = ""; | ||
if (spaces > 0) { | ||
result += new Array(spaces + 1).join(" "); | ||
} | ||
if (tabs > 0) { | ||
result += new Array(tabs + 1).join("\t"); | ||
} | ||
result += info.line.slice(info.sliceStart, info.sliceEnd); | ||
parts.push(result); | ||
if (spaces > 0) { | ||
result += new Array(spaces + 1).join(" "); | ||
} | ||
return parts.join(options.lineTerminator); | ||
result += info.line.slice(info.sliceStart, info.sliceEnd); | ||
parts.push(result); | ||
} | ||
return parts.join(options.lineTerminator); | ||
}; | ||
Lp.isEmpty = function() { | ||
return this.length < 2 && this.getLineLength(1) < 1; | ||
return this.length < 2 && this.getLineLength(1) < 1; | ||
}; | ||
Lp.join = function(elements) { | ||
var separator = this; | ||
var separatorSecret = getSecret(separator); | ||
var infos = []; | ||
var mappings = []; | ||
var prevInfo; | ||
var separator = this; | ||
var separatorSecret = getSecret(separator); | ||
var infos = []; | ||
var mappings = []; | ||
var prevInfo; | ||
function appendSecret(secret) { | ||
if (secret === null) | ||
return; | ||
function appendSecret(secret) { | ||
if (secret === null) | ||
return; | ||
if (prevInfo) { | ||
var info = secret.infos[0]; | ||
var indent = new Array(info.indent + 1).join(" "); | ||
var prevLine = infos.length; | ||
var prevColumn = Math.max(prevInfo.indent, 0) + | ||
prevInfo.sliceEnd - prevInfo.sliceStart; | ||
if (prevInfo) { | ||
var info = secret.infos[0]; | ||
var indent = new Array(info.indent + 1).join(" "); | ||
var prevLine = infos.length; | ||
var prevColumn = Math.max(prevInfo.indent, 0) + | ||
prevInfo.sliceEnd - prevInfo.sliceStart; | ||
prevInfo.line = prevInfo.line.slice( | ||
0, prevInfo.sliceEnd) + indent + info.line.slice( | ||
info.sliceStart, info.sliceEnd); | ||
prevInfo.line = prevInfo.line.slice( | ||
0, prevInfo.sliceEnd) + indent + info.line.slice( | ||
info.sliceStart, info.sliceEnd); | ||
// If any part of a line is indentation-locked, the whole line | ||
// will be indentation-locked. | ||
prevInfo.locked = prevInfo.locked || info.locked; | ||
// If any part of a line is indentation-locked, the whole line | ||
// will be indentation-locked. | ||
prevInfo.locked = prevInfo.locked || info.locked; | ||
prevInfo.sliceEnd = prevInfo.line.length; | ||
prevInfo.sliceEnd = prevInfo.line.length; | ||
if (secret.mappings.length > 0) { | ||
secret.mappings.forEach(function(mapping) { | ||
mappings.push(mapping.add(prevLine, prevColumn)); | ||
}); | ||
} | ||
} else if (secret.mappings.length > 0) { | ||
mappings.push.apply(mappings, secret.mappings); | ||
} | ||
secret.infos.forEach(function(info, i) { | ||
if (!prevInfo || i > 0) { | ||
prevInfo = copyLineInfo(info); | ||
infos.push(prevInfo); | ||
} | ||
if (secret.mappings.length > 0) { | ||
secret.mappings.forEach(function(mapping) { | ||
mappings.push(mapping.add(prevLine, prevColumn)); | ||
}); | ||
} | ||
} | ||
function appendWithSeparator(secret, i) { | ||
if (i > 0) | ||
appendSecret(separatorSecret); | ||
appendSecret(secret); | ||
} else if (secret.mappings.length > 0) { | ||
mappings.push.apply(mappings, secret.mappings); | ||
} | ||
elements.map(function(elem) { | ||
var lines = fromString(elem); | ||
if (lines.isEmpty()) | ||
return null; | ||
return getSecret(lines); | ||
}).forEach(separator.isEmpty() | ||
? appendSecret | ||
: appendWithSeparator); | ||
secret.infos.forEach(function(info, i) { | ||
if (!prevInfo || i > 0) { | ||
prevInfo = copyLineInfo(info); | ||
infos.push(prevInfo); | ||
} | ||
}); | ||
} | ||
if (infos.length < 1) | ||
return emptyLines; | ||
function appendWithSeparator(secret, i) { | ||
if (i > 0) | ||
appendSecret(separatorSecret); | ||
appendSecret(secret); | ||
} | ||
var lines = new Lines(infos); | ||
elements.map(function(elem) { | ||
var lines = fromString(elem); | ||
if (lines.isEmpty()) | ||
return null; | ||
return getSecret(lines); | ||
}).forEach(separator.isEmpty() | ||
? appendSecret | ||
: appendWithSeparator); | ||
getSecret(lines).mappings = mappings; | ||
if (infos.length < 1) | ||
return emptyLines; | ||
return lines; | ||
var lines = new Lines(infos); | ||
getSecret(lines).mappings = mappings; | ||
return lines; | ||
}; | ||
exports.concat = function(elements) { | ||
return emptyLines.join(elements); | ||
return emptyLines.join(elements); | ||
}; | ||
Lp.concat = function(other) { | ||
var args = arguments, | ||
list = [this]; | ||
list.push.apply(list, args); | ||
assert.strictEqual(list.length, args.length + 1); | ||
return emptyLines.join(list); | ||
var args = arguments, | ||
list = [this]; | ||
list.push.apply(list, args); | ||
assert.strictEqual(list.length, args.length + 1); | ||
return emptyLines.join(list); | ||
}; | ||
@@ -899,0 +904,0 @@ |
@@ -309,2 +309,3 @@ var assert = require("assert"); | ||
case "SpreadPropertyPattern": | ||
case "ObjectTypeSpreadProperty": | ||
case "RestElement": | ||
@@ -311,0 +312,0 @@ return concat(["...", path.call(print, "argument")]); |
@@ -15,3 +15,3 @@ { | ||
], | ||
"version": "0.12.6", | ||
"version": "0.12.7", | ||
"homepage": "http://github.com/benjamn/recast", | ||
@@ -32,7 +32,7 @@ "repository": { | ||
"dependencies": { | ||
"ast-types": "0.9.11", | ||
"ast-types": "0.9.12", | ||
"core-js": "^2.4.1", | ||
"esprima": "~4.0.0", | ||
"private": "~0.1.5", | ||
"source-map": "~0.5.0" | ||
"source-map": "~0.6.1" | ||
}, | ||
@@ -42,6 +42,7 @@ "devDependencies": { | ||
"babel-preset-es2015": "^6.22.0", | ||
"babylon": "~6.17.0", | ||
"babylon": "~6.18.0", | ||
"esprima-fb": "^15001.1001.0-dev-harmony-fb", | ||
"mocha": "~3.4.2", | ||
"reify": "^0.11.21", | ||
"mocha": "~4.0.1", | ||
"flow-parser": "^0.55.0", | ||
"reify": "^0.12.3", | ||
"semver": "^5.3.0" | ||
@@ -48,0 +49,0 @@ }, |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
195238
4377
8
+ Addedast-types@0.9.12(transitive)
+ Addedsource-map@0.6.1(transitive)
- Removedast-types@0.9.11(transitive)
- Removedsource-map@0.5.7(transitive)
Updatedast-types@0.9.12
Updatedsource-map@~0.6.1