function _createContextInfo(token, tokenType, offset, keyName, valueName, parentKeyName, isArray, exclusionList, shouldReplace) {
return {
token: token || null,
tokenType: tokenType || null,
offset: offset || 0,
keyName: keyName || null,
valueName: valueName || null,
parentKeyName: parentKeyName || null,
isArray: isArray || false,
exclusionList: exclusionList || [],
shouldReplace: shouldReplace || false
};
}
function _getExclusionList(editor, constPos) {
var ctxPrev, ctxNext, exclusionList = [], pos, braceParity;
// Move back to find exclusions.
pos = $.extend({}, constPos);
braceParity = 1;
ctxPrev = TokenUtils.getInitialContext(editor._codeMirror, pos);
while (TokenUtils.moveSkippingWhitespace(TokenUtils.movePrevToken, ctxPrev)) {
if (ctxPrev.token.type === null) {
if (ctxPrev.token.string === "}") {
braceParity++;
} else if (ctxPrev.token.string === "{") {
braceParity--;
}
}
if (braceParity === 1 && ctxPrev.token.type === "string property") {
exclusionList.push(stripQuotes(ctxPrev.token.string));
} else if (braceParity === 0) {
break;
}
}
// Move forward and find exclusions.
pos = $.extend({}, constPos);
braceParity = 1;
ctxNext = TokenUtils.getInitialContext(editor._codeMirror, pos);
while (TokenUtils.moveSkippingWhitespace(TokenUtils.moveNextToken, ctxNext)) {
if (ctxNext.token.type === null) {
if (ctxNext.token.string === "{") {
braceParity++;
} else if (ctxNext.token.string === "}") {
braceParity--;
}
}
if (braceParity === 1 && ctxNext.token.type === "string property") {
exclusionList.push(stripQuotes(ctxNext.token.string));
} else if (braceParity === 0) {
break;
}
}
return exclusionList;
}
function _getParentKeyName(ctx) {
var parentKeyName, braceParity = 1, hasColon;
// Move the context back to find the parent key.
while (TokenUtils.moveSkippingWhitespace(TokenUtils.movePrevToken, ctx)) {
if (ctx.token.type === null) {
if (ctx.token.string === "}") {
braceParity++;
} else if (ctx.token.string === "{") {
braceParity--;
}
}
if (braceParity === 0) {
while (TokenUtils.moveSkippingWhitespace(TokenUtils.movePrevToken, ctx)) {
if (ctx.token.type === null && ctx.token.string === ":") {
hasColon = true;
} else if (ctx.token.type === "string property") {
parentKeyName = stripQuotes(ctx.token.string);
break;
}
}
break;
}
}
if (parentKeyName && hasColon) {
return parentKeyName;
}
return null;
}
Returns context info at a given position in editor
function getContextInfo(editor, constPos, requireParent, requireNextToken) {
var pos, ctx, ctxPrev, ctxNext, offset, keyName, valueName, parentKeyName,
isArray, exclusionList, hasColon, hasComma, hasBracket, shouldReplace;
pos = $.extend({}, constPos);
ctx = TokenUtils.getInitialContext(editor._codeMirror, pos);
offset = TokenUtils.offsetInToken(ctx);
if (ctx.token && ctx.token.type === "string property") {
// String literals used as keys.
// Disallow hints if cursor is out of the string.
if (/^['"]$/.test(ctx.token.string.substr(-1, 1)) &&
ctx.token.string.length !== 1 && ctx.token.end === pos.ch) {
return null;
}
keyName = stripQuotes(ctx.token.string);
// Get parent key name.
if (requireParent) {
ctxPrev = $.extend(true, {}, ctx);
parentKeyName = stripQuotes(_getParentKeyName(ctxPrev));
}
// Check if the key is followed by a colon, so we should not append colon again.
ctxNext = $.extend(true, {}, ctx);
TokenUtils.moveSkippingWhitespace(TokenUtils.moveNextToken, ctxNext);
if (ctxNext.token.type === null && ctxNext.token.string === ":") {
shouldReplace = true;
}
// Get an exclusion list of properties.
pos = $.extend({}, constPos);
exclusionList = _getExclusionList(editor, pos);
return _createContextInfo(ctx.token, TOKEN_KEY, offset, keyName, valueName, parentKeyName, null, exclusionList, shouldReplace);
} else if (ctx.token && (valueTokenTypes.indexOf(ctx.token.type) !== -1 ||
(ctx.token.type === null && regexAllowedChars.test(ctx.token.string)))) {
// Boolean, String, Number and variable literal values.
// Disallow hints if cursor is out of the string.
if (ctx.token.type === "string" && /^['"]$/.test(ctx.token.string.substr(-1, 1)) &&
ctx.token.string.length !== 1 && ctx.token.end === pos.ch) {
return null;
}
valueName = ctx.token.string;
// Check the current token
if (ctx.token.type === null) {
if (ctx.token.string === ":") {
hasColon = true;
} else if (ctx.token.string === ",") {
hasComma = true;
} else if (ctx.token.string === "[") {
hasBracket = true;
}
}
// move context back and find corresponding key name.
ctxPrev = $.extend(true, {}, ctx);
while (TokenUtils.moveSkippingWhitespace(TokenUtils.movePrevToken, ctxPrev)) {
if (ctxPrev.token.type === "string property") {
keyName = stripQuotes(ctxPrev.token.string);
break;
} else if (ctxPrev.token.type === null) {
if (ctxPrev.token.string === ":") {
hasColon = true;
} else if (ctxPrev.token.string === ",") {
hasComma = true;
} else if (ctxPrev.token.string === "[") {
hasBracket = true;
} else {
return null;
}
} else if (!hasComma) {
return null;
}
}
// If no key name or colon found OR
// If we have a comma but no opening bracket, return null.
if ((!keyName || !hasColon) || (hasComma && !hasBracket)) {
return null;
} else {
isArray = hasBracket;
}
// Get parent key name.
if (requireParent) {
ctxPrev = $.extend(true, {}, ctx);
parentKeyName = stripQuotes(_getParentKeyName(ctxPrev));
}
// Check if we can replace the next token of a value.
ctxNext = $.extend(true, {}, ctx);
TokenUtils.moveNextToken(ctxNext);
if (requireNextToken && valueTokenTypes.indexOf(ctxNext.token.type) !== -1) {
shouldReplace = true;
}
return _createContextInfo((shouldReplace) ? ctxNext.token : ctx.token, TOKEN_VALUE, offset, keyName, valueName, parentKeyName, isArray, null, shouldReplace);
}
return null;
}
// Expose public API.
exports.TOKEN_KEY = TOKEN_KEY;
exports.TOKEN_VALUE = TOKEN_VALUE;
exports.regexAllowedChars = regexAllowedChars;
exports.getContextInfo = getContextInfo;
exports.stripQuotes = stripQuotes;
});
Removes the quotes around a string
function stripQuotes(string) {
if (string) {
if (/^['"]$/.test(string.charAt(0))) {
string = string.substr(1);
}
if (/^['"]$/.test(string.substr(-1, 1))) {
string = string.substr(0, string.length - 1);
}
}
return string;
}